Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / source / identifier_test.go
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package source
6
7 import (
8         "bytes"
9         "go/ast"
10         "go/parser"
11         "go/token"
12         "go/types"
13         "testing"
14 )
15
16 func TestSearchForEnclosing(t *testing.T) {
17         tests := []struct {
18                 desc string
19                 // For convenience, consider the first occurence of the identifier "X" in
20                 // src.
21                 src string
22                 // By convention, "" means no type found.
23                 wantTypeName string
24         }{
25                 {
26                         desc:         "self enclosing",
27                         src:          `package a; type X struct {}`,
28                         wantTypeName: "X",
29                 },
30                 {
31                         // TODO(rFindley): is this correct, or do we want to resolve I2 here?
32                         desc:         "embedded interface in interface",
33                         src:          `package a; var y = i1.X; type i1 interface {I2}; type I2 interface{X()}`,
34                         wantTypeName: "",
35                 },
36                 {
37                         desc:         "embedded interface in struct",
38                         src:          `package a; var y = t.X; type t struct {I}; type I interface{X()}`,
39                         wantTypeName: "I",
40                 },
41                 {
42                         desc:         "double embedding",
43                         src:          `package a; var y = t1.X; type t1 struct {t2}; type t2 struct {I}; type I interface{X()}`,
44                         wantTypeName: "I",
45                 },
46                 {
47                         desc:         "struct field",
48                         src:          `package a; type T struct { X int }`,
49                         wantTypeName: "T",
50                 },
51                 {
52                         desc:         "nested struct field",
53                         src:          `package a; type T struct { E struct { X int } }`,
54                         wantTypeName: "T",
55                 },
56                 {
57                         desc:         "slice entry",
58                         src:          `package a; type T []int; var S = T{X}; var X int = 2`,
59                         wantTypeName: "T",
60                 },
61                 {
62                         desc:         "struct pointer literal",
63                         src:          `package a; type T struct {i int}; var L = &T{X}; const X = 2`,
64                         wantTypeName: "T",
65                 },
66         }
67
68         for _, test := range tests {
69                 test := test
70                 t.Run(test.desc, func(t *testing.T) {
71                         fset := token.NewFileSet()
72                         file, err := parser.ParseFile(fset, "a.go", test.src, parser.AllErrors)
73                         if err != nil {
74                                 t.Fatal(err)
75                         }
76                         column := 1 + bytes.IndexRune([]byte(test.src), 'X')
77                         pos := posAt(1, column, fset, "a.go")
78                         path := pathEnclosingObjNode(file, pos)
79                         if path == nil {
80                                 t.Fatalf("no ident found at (1, %d)", column)
81                         }
82                         info := newInfo()
83                         if _, err = (*types.Config)(nil).Check("p", fset, []*ast.File{file}, info); err != nil {
84                                 t.Fatal(err)
85                         }
86                         typ := searchForEnclosing(info, path)
87                         if typ == nil {
88                                 if test.wantTypeName != "" {
89                                         t.Errorf("searchForEnclosing(...) = <nil>, want %q", test.wantTypeName)
90                                 }
91                                 return
92                         }
93                         if got := typ.(*types.Named).Obj().Name(); got != test.wantTypeName {
94                                 t.Errorf("searchForEnclosing(...) = %q, want %q", got, test.wantTypeName)
95                         }
96                 })
97         }
98 }
99
100 // posAt returns the token.Pos corresponding to the 1-based (line, column)
101 // coordinates in the file fname of fset.
102 func posAt(line, column int, fset *token.FileSet, fname string) token.Pos {
103         var tok *token.File
104         fset.Iterate(func(f *token.File) bool {
105                 if f.Name() == fname {
106                         tok = f
107                         return false
108                 }
109                 return true
110         })
111         if tok == nil {
112                 return token.NoPos
113         }
114         start := tok.LineStart(line)
115         return start + token.Pos(column-1)
116 }
117
118 // newInfo returns a types.Info with all maps populated.
119 func newInfo() *types.Info {
120         return &types.Info{
121                 Types:      make(map[ast.Expr]types.TypeAndValue),
122                 Defs:       make(map[*ast.Ident]types.Object),
123                 Uses:       make(map[*ast.Ident]types.Object),
124                 Implicits:  make(map[ast.Node]types.Object),
125                 Selections: make(map[*ast.SelectorExpr]*types.Selection),
126                 Scopes:     make(map[ast.Node]*types.Scope),
127         }
128 }