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 / identifier_test.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/identifier_test.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/source/identifier_test.go
new file mode 100644 (file)
index 0000000..f07e401
--- /dev/null
@@ -0,0 +1,128 @@
+// 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"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "go/types"
+       "testing"
+)
+
+func TestSearchForEnclosing(t *testing.T) {
+       tests := []struct {
+               desc string
+               // For convenience, consider the first occurence of the identifier "X" in
+               // src.
+               src string
+               // By convention, "" means no type found.
+               wantTypeName string
+       }{
+               {
+                       desc:         "self enclosing",
+                       src:          `package a; type X struct {}`,
+                       wantTypeName: "X",
+               },
+               {
+                       // TODO(rFindley): is this correct, or do we want to resolve I2 here?
+                       desc:         "embedded interface in interface",
+                       src:          `package a; var y = i1.X; type i1 interface {I2}; type I2 interface{X()}`,
+                       wantTypeName: "",
+               },
+               {
+                       desc:         "embedded interface in struct",
+                       src:          `package a; var y = t.X; type t struct {I}; type I interface{X()}`,
+                       wantTypeName: "I",
+               },
+               {
+                       desc:         "double embedding",
+                       src:          `package a; var y = t1.X; type t1 struct {t2}; type t2 struct {I}; type I interface{X()}`,
+                       wantTypeName: "I",
+               },
+               {
+                       desc:         "struct field",
+                       src:          `package a; type T struct { X int }`,
+                       wantTypeName: "T",
+               },
+               {
+                       desc:         "nested struct field",
+                       src:          `package a; type T struct { E struct { X int } }`,
+                       wantTypeName: "T",
+               },
+               {
+                       desc:         "slice entry",
+                       src:          `package a; type T []int; var S = T{X}; var X int = 2`,
+                       wantTypeName: "T",
+               },
+               {
+                       desc:         "struct pointer literal",
+                       src:          `package a; type T struct {i int}; var L = &T{X}; const X = 2`,
+                       wantTypeName: "T",
+               },
+       }
+
+       for _, test := range tests {
+               test := test
+               t.Run(test.desc, func(t *testing.T) {
+                       fset := token.NewFileSet()
+                       file, err := parser.ParseFile(fset, "a.go", test.src, parser.AllErrors)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       column := 1 + bytes.IndexRune([]byte(test.src), 'X')
+                       pos := posAt(1, column, fset, "a.go")
+                       path := pathEnclosingObjNode(file, pos)
+                       if path == nil {
+                               t.Fatalf("no ident found at (1, %d)", column)
+                       }
+                       info := newInfo()
+                       if _, err = (*types.Config)(nil).Check("p", fset, []*ast.File{file}, info); err != nil {
+                               t.Fatal(err)
+                       }
+                       typ := searchForEnclosing(info, path)
+                       if typ == nil {
+                               if test.wantTypeName != "" {
+                                       t.Errorf("searchForEnclosing(...) = <nil>, want %q", test.wantTypeName)
+                               }
+                               return
+                       }
+                       if got := typ.(*types.Named).Obj().Name(); got != test.wantTypeName {
+                               t.Errorf("searchForEnclosing(...) = %q, want %q", got, test.wantTypeName)
+                       }
+               })
+       }
+}
+
+// posAt returns the token.Pos corresponding to the 1-based (line, column)
+// coordinates in the file fname of fset.
+func posAt(line, column int, fset *token.FileSet, fname string) token.Pos {
+       var tok *token.File
+       fset.Iterate(func(f *token.File) bool {
+               if f.Name() == fname {
+                       tok = f
+                       return false
+               }
+               return true
+       })
+       if tok == nil {
+               return token.NoPos
+       }
+       start := tok.LineStart(line)
+       return start + token.Pos(column-1)
+}
+
+// newInfo returns a types.Info with all maps populated.
+func newInfo() *types.Info {
+       return &types.Info{
+               Types:      make(map[ast.Expr]types.TypeAndValue),
+               Defs:       make(map[*ast.Ident]types.Object),
+               Uses:       make(map[*ast.Ident]types.Object),
+               Implicits:  make(map[ast.Node]types.Object),
+               Selections: make(map[*ast.SelectorExpr]*types.Selection),
+               Scopes:     make(map[ast.Node]*types.Scope),
+       }
+}