Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / source / types_format.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/source/types_format.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/source/types_format.go
new file mode 100644 (file)
index 0000000..5ddd8e0
--- /dev/null
@@ -0,0 +1,421 @@
+// Copyright 2020 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 (
+       "bytes"
+       "context"
+       "fmt"
+       "go/ast"
+       "go/doc"
+       "go/printer"
+       "go/token"
+       "go/types"
+       "strings"
+
+       "golang.org/x/tools/internal/event"
+       "golang.org/x/tools/internal/lsp/debug/tag"
+       "golang.org/x/tools/internal/lsp/protocol"
+)
+
+// FormatType returns the detail and kind for a types.Type.
+func FormatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) {
+       if types.IsInterface(typ) {
+               detail = "interface{...}"
+               kind = protocol.InterfaceCompletion
+       } else if _, ok := typ.(*types.Struct); ok {
+               detail = "struct{...}"
+               kind = protocol.StructCompletion
+       } else if typ != typ.Underlying() {
+               detail, kind = FormatType(typ.Underlying(), qf)
+       } else {
+               detail = types.TypeString(typ, qf)
+               kind = protocol.ClassCompletion
+       }
+       return detail, kind
+}
+
+type signature struct {
+       name, doc        string
+       params, results  []string
+       variadic         bool
+       needResultParens bool
+}
+
+func (s *signature) Format() string {
+       var b strings.Builder
+       b.WriteByte('(')
+       for i, p := range s.params {
+               if i > 0 {
+                       b.WriteString(", ")
+               }
+               b.WriteString(p)
+       }
+       b.WriteByte(')')
+
+       // Add space between parameters and results.
+       if len(s.results) > 0 {
+               b.WriteByte(' ')
+       }
+       if s.needResultParens {
+               b.WriteByte('(')
+       }
+       for i, r := range s.results {
+               if i > 0 {
+                       b.WriteString(", ")
+               }
+               b.WriteString(r)
+       }
+       if s.needResultParens {
+               b.WriteByte(')')
+       }
+       return b.String()
+}
+
+func (s *signature) Params() []string {
+       return s.params
+}
+
+// NewBuiltinSignature returns signature for the builtin object with a given
+// name, if a builtin object with the name exists.
+func NewBuiltinSignature(ctx context.Context, s Snapshot, name string) (*signature, error) {
+       builtin, err := s.BuiltinPackage(ctx)
+       if err != nil {
+               return nil, err
+       }
+       obj := builtin.Package.Scope.Lookup(name)
+       if obj == nil {
+               return nil, fmt.Errorf("no builtin object for %s", name)
+       }
+       decl, ok := obj.Decl.(*ast.FuncDecl)
+       if !ok {
+               return nil, fmt.Errorf("no function declaration for builtin: %s", name)
+       }
+       if decl.Type == nil {
+               return nil, fmt.Errorf("no type for builtin decl %s", decl.Name)
+       }
+       var variadic bool
+       if decl.Type.Params.List != nil {
+               numParams := len(decl.Type.Params.List)
+               lastParam := decl.Type.Params.List[numParams-1]
+               if _, ok := lastParam.Type.(*ast.Ellipsis); ok {
+                       variadic = true
+               }
+       }
+       params, _ := formatFieldList(ctx, s, decl.Type.Params, variadic)
+       results, needResultParens := formatFieldList(ctx, s, decl.Type.Results, false)
+       d := decl.Doc.Text()
+       switch s.View().Options().HoverKind {
+       case SynopsisDocumentation:
+               d = doc.Synopsis(d)
+       case NoDocumentation:
+               d = ""
+       }
+       return &signature{
+               doc:              d,
+               name:             name,
+               needResultParens: needResultParens,
+               params:           params,
+               results:          results,
+               variadic:         variadic,
+       }, nil
+}
+
+var replacer = strings.NewReplacer(
+       `ComplexType`, `complex128`,
+       `FloatType`, `float64`,
+       `IntegerType`, `int`,
+)
+
+func formatFieldList(ctx context.Context, snapshot Snapshot, list *ast.FieldList, variadic bool) ([]string, bool) {
+       if list == nil {
+               return nil, false
+       }
+       var writeResultParens bool
+       var result []string
+       for i := 0; i < len(list.List); i++ {
+               if i >= 1 {
+                       writeResultParens = true
+               }
+               p := list.List[i]
+               cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
+               b := &bytes.Buffer{}
+               if err := cfg.Fprint(b, snapshot.FileSet(), p.Type); err != nil {
+                       event.Error(ctx, "unable to print type", nil, tag.Type.Of(p.Type))
+                       continue
+               }
+               typ := replacer.Replace(b.String())
+               if len(p.Names) == 0 {
+                       result = append(result, typ)
+               }
+               for _, name := range p.Names {
+                       if name.Name != "" {
+                               if i == 0 {
+                                       writeResultParens = true
+                               }
+                               result = append(result, fmt.Sprintf("%s %s", name.Name, typ))
+                       } else {
+                               result = append(result, typ)
+                       }
+               }
+       }
+       if variadic {
+               result[len(result)-1] = strings.Replace(result[len(result)-1], "[]", "...", 1)
+       }
+       return result, writeResultParens
+}
+
+// NewSignature returns formatted signature for a types.Signature struct.
+func NewSignature(ctx context.Context, s Snapshot, pkg Package, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier) *signature {
+       params := make([]string, 0, sig.Params().Len())
+       for i := 0; i < sig.Params().Len(); i++ {
+               el := sig.Params().At(i)
+               typ := FormatVarType(ctx, s, pkg, el, qf)
+               p := typ
+               if el.Name() != "" {
+                       p = el.Name() + " " + typ
+               }
+               params = append(params, p)
+       }
+       var needResultParens bool
+       results := make([]string, 0, sig.Results().Len())
+       for i := 0; i < sig.Results().Len(); i++ {
+               if i >= 1 {
+                       needResultParens = true
+               }
+               el := sig.Results().At(i)
+               typ := FormatVarType(ctx, s, pkg, el, qf)
+               if el.Name() == "" {
+                       results = append(results, typ)
+               } else {
+                       if i == 0 {
+                               needResultParens = true
+                       }
+                       results = append(results, el.Name()+" "+typ)
+               }
+       }
+       var d string
+       if comment != nil {
+               d = comment.Text()
+       }
+       switch s.View().Options().HoverKind {
+       case SynopsisDocumentation:
+               d = doc.Synopsis(d)
+       case NoDocumentation:
+               d = ""
+       }
+       return &signature{
+               doc:              d,
+               params:           params,
+               results:          results,
+               variadic:         sig.Variadic(),
+               needResultParens: needResultParens,
+       }
+}
+
+// FormatVarType formats a *types.Var, accounting for type aliases.
+// To do this, it looks in the AST of the file in which the object is declared.
+// On any errors, it always fallbacks back to types.TypeString.
+func FormatVarType(ctx context.Context, snapshot Snapshot, srcpkg Package, obj *types.Var, qf types.Qualifier) string {
+       pgf, pkg, err := FindPosInPackage(snapshot, srcpkg, obj.Pos())
+       if err != nil {
+               return types.TypeString(obj.Type(), qf)
+       }
+
+       expr, err := varType(ctx, snapshot, pgf, obj)
+       if err != nil {
+               return types.TypeString(obj.Type(), qf)
+       }
+
+       // The type names in the AST may not be correctly qualified.
+       // Determine the package name to use based on the package that originated
+       // the query and the package in which the type is declared.
+       // We then qualify the value by cloning the AST node and editing it.
+       clonedInfo := make(map[token.Pos]*types.PkgName)
+       qualified := cloneExpr(expr, pkg.GetTypesInfo(), clonedInfo)
+
+       // If the request came from a different package than the one in which the
+       // types are defined, we may need to modify the qualifiers.
+       qualified = qualifyExpr(qualified, srcpkg, pkg, clonedInfo, qf)
+       fmted := FormatNode(snapshot.FileSet(), qualified)
+       return fmted
+}
+
+// varType returns the type expression for a *types.Var.
+func varType(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile, obj *types.Var) (ast.Expr, error) {
+       posToField, err := snapshot.PosToField(ctx, pgf)
+       if err != nil {
+               return nil, err
+       }
+       field := posToField[obj.Pos()]
+       if field == nil {
+               return nil, fmt.Errorf("no declaration for object %s", obj.Name())
+       }
+       typ, ok := field.Type.(ast.Expr)
+       if !ok {
+               return nil, fmt.Errorf("unexpected type for node (%T)", field.Type)
+       }
+       return typ, nil
+}
+
+// qualifyExpr applies the "pkgName." prefix to any *ast.Ident in the expr.
+func qualifyExpr(expr ast.Expr, srcpkg, pkg Package, clonedInfo map[token.Pos]*types.PkgName, qf types.Qualifier) ast.Expr {
+       ast.Inspect(expr, func(n ast.Node) bool {
+               switch n := n.(type) {
+               case *ast.ArrayType, *ast.ChanType, *ast.Ellipsis,
+                       *ast.FuncType, *ast.MapType, *ast.ParenExpr,
+                       *ast.StarExpr, *ast.StructType:
+                       // These are the only types that are cloned by cloneExpr below,
+                       // so these are the only types that we can traverse and potentially
+                       // modify. This is not an ideal approach, but it works for now.
+                       return true
+               case *ast.SelectorExpr:
+                       // We may need to change any selectors in which the X is a package
+                       // name and the Sel is exported.
+                       x, ok := n.X.(*ast.Ident)
+                       if !ok {
+                               return false
+                       }
+                       obj, ok := clonedInfo[x.Pos()]
+                       if !ok {
+                               return false
+                       }
+                       pkgName := qf(obj.Imported())
+                       if pkgName != "" {
+                               x.Name = pkgName
+                       }
+                       return false
+               case *ast.Ident:
+                       if srcpkg == pkg {
+                               return false
+                       }
+                       // Only add the qualifier if the identifier is exported.
+                       if ast.IsExported(n.Name) {
+                               pkgName := qf(pkg.GetTypes())
+                               n.Name = pkgName + "." + n.Name
+                       }
+               }
+               return false
+       })
+       return expr
+}
+
+// cloneExpr only clones expressions that appear in the parameters or return
+// values of a function declaration. The original expression may be returned
+// to the caller in 2 cases:
+//    (1) The expression has no pointer fields.
+//    (2) The expression cannot appear in an *ast.FuncType, making it
+//        unnecessary to clone.
+// This function also keeps track of selector expressions in which the X is a
+// package name and marks them in a map along with their type information, so
+// that this information can be used when rewriting the expression.
+//
+// NOTE: This function is tailored to the use case of qualifyExpr, and should
+// be used with caution.
+func cloneExpr(expr ast.Expr, info *types.Info, clonedInfo map[token.Pos]*types.PkgName) ast.Expr {
+       switch expr := expr.(type) {
+       case *ast.ArrayType:
+               return &ast.ArrayType{
+                       Lbrack: expr.Lbrack,
+                       Elt:    cloneExpr(expr.Elt, info, clonedInfo),
+                       Len:    expr.Len,
+               }
+       case *ast.ChanType:
+               return &ast.ChanType{
+                       Arrow: expr.Arrow,
+                       Begin: expr.Begin,
+                       Dir:   expr.Dir,
+                       Value: cloneExpr(expr.Value, info, clonedInfo),
+               }
+       case *ast.Ellipsis:
+               return &ast.Ellipsis{
+                       Ellipsis: expr.Ellipsis,
+                       Elt:      cloneExpr(expr.Elt, info, clonedInfo),
+               }
+       case *ast.FuncType:
+               return &ast.FuncType{
+                       Func:    expr.Func,
+                       Params:  cloneFieldList(expr.Params, info, clonedInfo),
+                       Results: cloneFieldList(expr.Results, info, clonedInfo),
+               }
+       case *ast.Ident:
+               return cloneIdent(expr)
+       case *ast.MapType:
+               return &ast.MapType{
+                       Map:   expr.Map,
+                       Key:   cloneExpr(expr.Key, info, clonedInfo),
+                       Value: cloneExpr(expr.Value, info, clonedInfo),
+               }
+       case *ast.ParenExpr:
+               return &ast.ParenExpr{
+                       Lparen: expr.Lparen,
+                       Rparen: expr.Rparen,
+                       X:      cloneExpr(expr.X, info, clonedInfo),
+               }
+       case *ast.SelectorExpr:
+               s := &ast.SelectorExpr{
+                       Sel: cloneIdent(expr.Sel),
+                       X:   cloneExpr(expr.X, info, clonedInfo),
+               }
+               if x, ok := expr.X.(*ast.Ident); ok && ast.IsExported(expr.Sel.Name) {
+                       if obj, ok := info.ObjectOf(x).(*types.PkgName); ok {
+                               clonedInfo[s.X.Pos()] = obj
+                       }
+               }
+               return s
+       case *ast.StarExpr:
+               return &ast.StarExpr{
+                       Star: expr.Star,
+                       X:    cloneExpr(expr.X, info, clonedInfo),
+               }
+       case *ast.StructType:
+               return &ast.StructType{
+                       Struct:     expr.Struct,
+                       Fields:     cloneFieldList(expr.Fields, info, clonedInfo),
+                       Incomplete: expr.Incomplete,
+               }
+       default:
+               return expr
+       }
+}
+
+func cloneFieldList(fl *ast.FieldList, info *types.Info, clonedInfo map[token.Pos]*types.PkgName) *ast.FieldList {
+       if fl == nil {
+               return nil
+       }
+       if fl.List == nil {
+               return &ast.FieldList{
+                       Closing: fl.Closing,
+                       Opening: fl.Opening,
+               }
+       }
+       list := make([]*ast.Field, 0, len(fl.List))
+       for _, f := range fl.List {
+               var names []*ast.Ident
+               for _, n := range f.Names {
+                       names = append(names, cloneIdent(n))
+               }
+               list = append(list, &ast.Field{
+                       Comment: f.Comment,
+                       Doc:     f.Doc,
+                       Names:   names,
+                       Tag:     f.Tag,
+                       Type:    cloneExpr(f.Type, info, clonedInfo),
+               })
+       }
+       return &ast.FieldList{
+               Closing: fl.Closing,
+               Opening: fl.Opening,
+               List:    list,
+       }
+}
+
+func cloneIdent(ident *ast.Ident) *ast.Ident {
+       return &ast.Ident{
+               NamePos: ident.NamePos,
+               Name:    ident.Name,
+               Obj:     ident.Obj,
+       }
+}