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 / references.go
1 // Copyright 2019 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         "context"
9         "go/ast"
10         "go/token"
11         "go/types"
12         "sort"
13
14         "golang.org/x/tools/internal/event"
15         "golang.org/x/tools/internal/lsp/protocol"
16         "golang.org/x/tools/internal/span"
17         errors "golang.org/x/xerrors"
18 )
19
20 // ReferenceInfo holds information about reference to an identifier in Go source.
21 type ReferenceInfo struct {
22         Name string
23         MappedRange
24         ident         *ast.Ident
25         obj           types.Object
26         pkg           Package
27         isDeclaration bool
28 }
29
30 // References returns a list of references for a given identifier within the packages
31 // containing i.File. Declarations appear first in the result.
32 func References(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position, includeDeclaration bool) ([]*ReferenceInfo, error) {
33         ctx, done := event.Start(ctx, "source.References")
34         defer done()
35
36         qualifiedObjs, err := qualifiedObjsAtProtocolPos(ctx, s, f, pp)
37         // Don't return references for builtin types.
38         if errors.Is(err, errBuiltin) {
39                 return nil, nil
40         }
41         if err != nil {
42                 return nil, err
43         }
44
45         refs, err := references(ctx, s, qualifiedObjs, includeDeclaration, true)
46         if err != nil {
47                 return nil, err
48         }
49
50         toSort := refs
51         if includeDeclaration {
52                 toSort = refs[1:]
53         }
54         sort.Slice(toSort, func(i, j int) bool {
55                 x := span.CompareURI(toSort[i].URI(), toSort[j].URI())
56                 if x == 0 {
57                         return toSort[i].ident.Pos() < toSort[j].ident.Pos()
58                 }
59                 return x < 0
60         })
61         return refs, nil
62 }
63
64 // references is a helper function to avoid recomputing qualifiedObjsAtProtocolPos.
65 func references(ctx context.Context, snapshot Snapshot, qos []qualifiedObject, includeDeclaration, includeInterfaceRefs bool) ([]*ReferenceInfo, error) {
66         var (
67                 references []*ReferenceInfo
68                 seen       = make(map[token.Position]bool)
69         )
70
71         filename := snapshot.FileSet().Position(qos[0].obj.Pos()).Filename
72         pgf, err := qos[0].pkg.File(span.URIFromPath(filename))
73         if err != nil {
74                 return nil, err
75         }
76         declIdent, err := findIdentifier(ctx, snapshot, qos[0].pkg, pgf.File, qos[0].obj.Pos())
77         if err != nil {
78                 return nil, err
79         }
80         // Make sure declaration is the first item in the response.
81         if includeDeclaration {
82                 references = append(references, &ReferenceInfo{
83                         MappedRange:   declIdent.MappedRange,
84                         Name:          qos[0].obj.Name(),
85                         ident:         declIdent.ident,
86                         obj:           qos[0].obj,
87                         pkg:           declIdent.pkg,
88                         isDeclaration: true,
89                 })
90         }
91
92         for _, qo := range qos {
93                 var searchPkgs []Package
94
95                 // Only search dependents if the object is exported.
96                 if qo.obj.Exported() {
97                         reverseDeps, err := snapshot.GetReverseDependencies(ctx, qo.pkg.ID())
98                         if err != nil {
99                                 return nil, err
100                         }
101                         searchPkgs = append(searchPkgs, reverseDeps...)
102                 }
103                 // Add the package in which the identifier is declared.
104                 searchPkgs = append(searchPkgs, qo.pkg)
105                 for _, pkg := range searchPkgs {
106                         for ident, obj := range pkg.GetTypesInfo().Uses {
107                                 if obj != qo.obj {
108                                         continue
109                                 }
110                                 pos := snapshot.FileSet().Position(ident.Pos())
111                                 if seen[pos] {
112                                         continue
113                                 }
114                                 seen[pos] = true
115                                 rng, err := posToMappedRange(snapshot, pkg, ident.Pos(), ident.End())
116                                 if err != nil {
117                                         return nil, err
118                                 }
119                                 references = append(references, &ReferenceInfo{
120                                         Name:        ident.Name,
121                                         ident:       ident,
122                                         pkg:         pkg,
123                                         obj:         obj,
124                                         MappedRange: rng,
125                                 })
126                         }
127                 }
128         }
129
130         if includeInterfaceRefs {
131                 declRange, err := declIdent.Range()
132                 if err != nil {
133                         return nil, err
134                 }
135                 fh, err := snapshot.GetFile(ctx, declIdent.URI())
136                 if err != nil {
137                         return nil, err
138                 }
139                 interfaceRefs, err := interfaceReferences(ctx, snapshot, fh, declRange.Start)
140                 if err != nil {
141                         return nil, err
142                 }
143                 references = append(references, interfaceRefs...)
144         }
145
146         return references, nil
147 }
148
149 // interfaceReferences returns the references to the interfaces implemeneted by
150 // the type or method at the given position.
151 func interfaceReferences(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position) ([]*ReferenceInfo, error) {
152         implementations, err := implementations(ctx, s, f, pp)
153         if err != nil {
154                 if errors.Is(err, ErrNotAType) {
155                         return nil, nil
156                 }
157                 return nil, err
158         }
159
160         var refs []*ReferenceInfo
161         for _, impl := range implementations {
162                 implRefs, err := references(ctx, s, []qualifiedObject{impl}, false, false)
163                 if err != nil {
164                         return nil, err
165                 }
166                 refs = append(refs, implRefs...)
167         }
168         return refs, nil
169 }