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 / cache / errors.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 cache
6
7 import (
8         "context"
9         "fmt"
10         "go/scanner"
11         "go/token"
12         "go/types"
13         "regexp"
14         "strconv"
15         "strings"
16
17         "golang.org/x/tools/go/analysis"
18         "golang.org/x/tools/go/packages"
19         "golang.org/x/tools/internal/analysisinternal"
20         "golang.org/x/tools/internal/event"
21         "golang.org/x/tools/internal/lsp/debug/tag"
22         "golang.org/x/tools/internal/lsp/protocol"
23         "golang.org/x/tools/internal/lsp/source"
24         "golang.org/x/tools/internal/span"
25         errors "golang.org/x/xerrors"
26 )
27
28 func sourceError(ctx context.Context, snapshot *snapshot, pkg *pkg, e interface{}) (*source.Error, error) {
29         fset := snapshot.view.session.cache.fset
30         var (
31                 spn           span.Span
32                 err           error
33                 msg, category string
34                 kind          source.ErrorKind
35                 fixes         []source.SuggestedFix
36                 related       []source.RelatedInformation
37         )
38         switch e := e.(type) {
39         case packages.Error:
40                 kind = toSourceErrorKind(e.Kind)
41                 var ok bool
42                 if msg, spn, ok = parseGoListImportCycleError(ctx, snapshot, e, pkg); ok {
43                         kind = source.TypeError
44                         break
45                 }
46                 if e.Pos == "" {
47                         spn = parseGoListError(e.Msg)
48
49                         // We may not have been able to parse a valid span.
50                         if _, err := spanToRange(snapshot, pkg, spn); err != nil {
51                                 return &source.Error{
52                                         URI:     spn.URI(),
53                                         Message: msg,
54                                         Kind:    kind,
55                                 }, nil
56                         }
57                 } else {
58                         spn = span.Parse(e.Pos)
59                 }
60         case *scanner.Error:
61                 msg = e.Msg
62                 kind = source.ParseError
63                 spn, err = scannerErrorRange(snapshot, pkg, e.Pos)
64                 if err != nil {
65                         if ctx.Err() != nil {
66                                 return nil, ctx.Err()
67                         }
68                         event.Error(ctx, "no span for scanner.Error pos", err, tag.Package.Of(pkg.ID()))
69                         spn = span.Parse(e.Pos.String())
70                 }
71
72         case scanner.ErrorList:
73                 // The first parser error is likely the root cause of the problem.
74                 if e.Len() <= 0 {
75                         return nil, errors.Errorf("no errors in %v", e)
76                 }
77                 msg = e[0].Msg
78                 kind = source.ParseError
79                 spn, err = scannerErrorRange(snapshot, pkg, e[0].Pos)
80                 if err != nil {
81                         if ctx.Err() != nil {
82                                 return nil, ctx.Err()
83                         }
84                         event.Error(ctx, "no span for scanner.Error pos", err, tag.Package.Of(pkg.ID()))
85                         spn = span.Parse(e[0].Pos.String())
86                 }
87         case types.Error:
88                 msg = e.Msg
89                 kind = source.TypeError
90                 if !e.Pos.IsValid() {
91                         return nil, fmt.Errorf("invalid position for type error %v", e)
92                 }
93                 spn, err = typeErrorRange(snapshot, fset, pkg, e.Pos)
94                 if err != nil {
95                         return nil, err
96                 }
97         case extendedError:
98                 perr := e.primary
99                 msg = perr.Msg
100                 kind = source.TypeError
101                 if !perr.Pos.IsValid() {
102                         return nil, fmt.Errorf("invalid position for type error %v", e)
103                 }
104                 spn, err = typeErrorRange(snapshot, fset, pkg, perr.Pos)
105                 if err != nil {
106                         return nil, err
107                 }
108                 for _, s := range e.secondaries {
109                         var x source.RelatedInformation
110                         x.Message = s.Msg
111                         xspn, err := typeErrorRange(snapshot, fset, pkg, s.Pos)
112                         if err != nil {
113                                 return nil, fmt.Errorf("invalid position for type error %v", s)
114                         }
115                         x.URI = xspn.URI()
116                         rng, err := spanToRange(snapshot, pkg, xspn)
117                         if err != nil {
118                                 return nil, err
119                         }
120                         x.Range = rng
121                         related = append(related, x)
122                 }
123         case *analysis.Diagnostic:
124                 spn, err = span.NewRange(fset, e.Pos, e.End).Span()
125                 if err != nil {
126                         return nil, err
127                 }
128                 msg = e.Message
129                 kind = source.Analysis
130                 category = e.Category
131                 fixes, err = suggestedFixes(snapshot, pkg, e)
132                 if err != nil {
133                         return nil, err
134                 }
135                 related, err = relatedInformation(snapshot, pkg, e)
136                 if err != nil {
137                         return nil, err
138                 }
139         default:
140                 panic(fmt.Sprintf("%T unexpected", e))
141         }
142         rng, err := spanToRange(snapshot, pkg, spn)
143         if err != nil {
144                 return nil, err
145         }
146         return &source.Error{
147                 URI:            spn.URI(),
148                 Range:          rng,
149                 Message:        msg,
150                 Kind:           kind,
151                 Category:       category,
152                 SuggestedFixes: fixes,
153                 Related:        related,
154         }, nil
155 }
156
157 func suggestedFixes(snapshot *snapshot, pkg *pkg, diag *analysis.Diagnostic) ([]source.SuggestedFix, error) {
158         var fixes []source.SuggestedFix
159         for _, fix := range diag.SuggestedFixes {
160                 edits := make(map[span.URI][]protocol.TextEdit)
161                 for _, e := range fix.TextEdits {
162                         spn, err := span.NewRange(snapshot.view.session.cache.fset, e.Pos, e.End).Span()
163                         if err != nil {
164                                 return nil, err
165                         }
166                         rng, err := spanToRange(snapshot, pkg, spn)
167                         if err != nil {
168                                 return nil, err
169                         }
170                         edits[spn.URI()] = append(edits[spn.URI()], protocol.TextEdit{
171                                 Range:   rng,
172                                 NewText: string(e.NewText),
173                         })
174                 }
175                 fixes = append(fixes, source.SuggestedFix{
176                         Title: fix.Message,
177                         Edits: edits,
178                 })
179         }
180         return fixes, nil
181 }
182
183 func relatedInformation(snapshot *snapshot, pkg *pkg, diag *analysis.Diagnostic) ([]source.RelatedInformation, error) {
184         var out []source.RelatedInformation
185         for _, related := range diag.Related {
186                 spn, err := span.NewRange(snapshot.view.session.cache.fset, related.Pos, related.End).Span()
187                 if err != nil {
188                         return nil, err
189                 }
190                 rng, err := spanToRange(snapshot, pkg, spn)
191                 if err != nil {
192                         return nil, err
193                 }
194                 out = append(out, source.RelatedInformation{
195                         URI:     spn.URI(),
196                         Range:   rng,
197                         Message: related.Message,
198                 })
199         }
200         return out, nil
201 }
202
203 func toSourceErrorKind(kind packages.ErrorKind) source.ErrorKind {
204         switch kind {
205         case packages.ListError:
206                 return source.ListError
207         case packages.ParseError:
208                 return source.ParseError
209         case packages.TypeError:
210                 return source.TypeError
211         default:
212                 return source.UnknownError
213         }
214 }
215
216 func typeErrorRange(snapshot *snapshot, fset *token.FileSet, pkg *pkg, pos token.Pos) (span.Span, error) {
217         posn := fset.Position(pos)
218         pgf, err := pkg.File(span.URIFromPath(posn.Filename))
219         if err != nil {
220                 return span.Span{}, err
221         }
222         return span.Range{
223                 FileSet:   fset,
224                 Start:     pos,
225                 End:       analysisinternal.TypeErrorEndPos(fset, pgf.Src, pos),
226                 Converter: pgf.Mapper.Converter,
227         }.Span()
228 }
229
230 func scannerErrorRange(snapshot *snapshot, pkg *pkg, posn token.Position) (span.Span, error) {
231         fset := snapshot.view.session.cache.fset
232         pgf, err := pkg.File(span.URIFromPath(posn.Filename))
233         if err != nil {
234                 return span.Span{}, err
235         }
236         pos := pgf.Tok.Pos(posn.Offset)
237         return span.NewRange(fset, pos, pos).Span()
238 }
239
240 // spanToRange converts a span.Span to a protocol.Range,
241 // assuming that the span belongs to the package whose diagnostics are being computed.
242 func spanToRange(snapshot *snapshot, pkg *pkg, spn span.Span) (protocol.Range, error) {
243         pgf, err := pkg.File(spn.URI())
244         if err != nil {
245                 return protocol.Range{}, err
246         }
247         return pgf.Mapper.Range(spn)
248 }
249
250 // parseGoListError attempts to parse a standard `go list` error message
251 // by stripping off the trailing error message.
252 //
253 // It works only on errors whose message is prefixed by colon,
254 // followed by a space (": "). For example:
255 //
256 //   attributes.go:13:1: expected 'package', found 'type'
257 //
258 func parseGoListError(input string) span.Span {
259         input = strings.TrimSpace(input)
260         msgIndex := strings.Index(input, ": ")
261         if msgIndex < 0 {
262                 return span.Parse(input)
263         }
264         return span.Parse(input[:msgIndex])
265 }
266
267 func parseGoListImportCycleError(ctx context.Context, snapshot *snapshot, e packages.Error, pkg *pkg) (string, span.Span, bool) {
268         re := regexp.MustCompile(`(.*): import stack: \[(.+)\]`)
269         matches := re.FindStringSubmatch(strings.TrimSpace(e.Msg))
270         if len(matches) < 3 {
271                 return e.Msg, span.Span{}, false
272         }
273         msg := matches[1]
274         importList := strings.Split(matches[2], " ")
275         // Since the error is relative to the current package. The import that is causing
276         // the import cycle error is the second one in the list.
277         if len(importList) < 2 {
278                 return msg, span.Span{}, false
279         }
280         // Imports have quotation marks around them.
281         circImp := strconv.Quote(importList[1])
282         for _, cgf := range pkg.compiledGoFiles {
283                 // Search file imports for the import that is causing the import cycle.
284                 for _, imp := range cgf.File.Imports {
285                         if imp.Path.Value == circImp {
286                                 spn, err := span.NewRange(snapshot.view.session.cache.fset, imp.Pos(), imp.End()).Span()
287                                 if err != nil {
288                                         return msg, span.Span{}, false
289                                 }
290                                 return msg, spn, true
291                         }
292                 }
293         }
294         return msg, span.Span{}, false
295 }