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 / go / packages / golist.go
1 // Copyright 2018 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 packages
6
7 import (
8         "bytes"
9         "context"
10         "encoding/json"
11         "fmt"
12         "go/types"
13         "io/ioutil"
14         "log"
15         "os"
16         "os/exec"
17         "path"
18         "path/filepath"
19         "reflect"
20         "sort"
21         "strconv"
22         "strings"
23         "sync"
24         "unicode"
25
26         "golang.org/x/tools/go/internal/packagesdriver"
27         "golang.org/x/tools/internal/gocommand"
28         "golang.org/x/xerrors"
29 )
30
31 // debug controls verbose logging.
32 var debug, _ = strconv.ParseBool(os.Getenv("GOPACKAGESDEBUG"))
33
34 // A goTooOldError reports that the go command
35 // found by exec.LookPath is too old to use the new go list behavior.
36 type goTooOldError struct {
37         error
38 }
39
40 // responseDeduper wraps a driverResponse, deduplicating its contents.
41 type responseDeduper struct {
42         seenRoots    map[string]bool
43         seenPackages map[string]*Package
44         dr           *driverResponse
45 }
46
47 func newDeduper() *responseDeduper {
48         return &responseDeduper{
49                 dr:           &driverResponse{},
50                 seenRoots:    map[string]bool{},
51                 seenPackages: map[string]*Package{},
52         }
53 }
54
55 // addAll fills in r with a driverResponse.
56 func (r *responseDeduper) addAll(dr *driverResponse) {
57         for _, pkg := range dr.Packages {
58                 r.addPackage(pkg)
59         }
60         for _, root := range dr.Roots {
61                 r.addRoot(root)
62         }
63 }
64
65 func (r *responseDeduper) addPackage(p *Package) {
66         if r.seenPackages[p.ID] != nil {
67                 return
68         }
69         r.seenPackages[p.ID] = p
70         r.dr.Packages = append(r.dr.Packages, p)
71 }
72
73 func (r *responseDeduper) addRoot(id string) {
74         if r.seenRoots[id] {
75                 return
76         }
77         r.seenRoots[id] = true
78         r.dr.Roots = append(r.dr.Roots, id)
79 }
80
81 type golistState struct {
82         cfg *Config
83         ctx context.Context
84
85         envOnce    sync.Once
86         goEnvError error
87         goEnv      map[string]string
88
89         rootsOnce     sync.Once
90         rootDirsError error
91         rootDirs      map[string]string
92
93         goVersionOnce  sync.Once
94         goVersionError error
95         goVersion      int // The X in Go 1.X.
96
97         // vendorDirs caches the (non)existence of vendor directories.
98         vendorDirs map[string]bool
99 }
100
101 // getEnv returns Go environment variables. Only specific variables are
102 // populated -- computing all of them is slow.
103 func (state *golistState) getEnv() (map[string]string, error) {
104         state.envOnce.Do(func() {
105                 var b *bytes.Buffer
106                 b, state.goEnvError = state.invokeGo("env", "-json", "GOMOD", "GOPATH")
107                 if state.goEnvError != nil {
108                         return
109                 }
110
111                 state.goEnv = make(map[string]string)
112                 decoder := json.NewDecoder(b)
113                 if state.goEnvError = decoder.Decode(&state.goEnv); state.goEnvError != nil {
114                         return
115                 }
116         })
117         return state.goEnv, state.goEnvError
118 }
119
120 // mustGetEnv is a convenience function that can be used if getEnv has already succeeded.
121 func (state *golistState) mustGetEnv() map[string]string {
122         env, err := state.getEnv()
123         if err != nil {
124                 panic(fmt.Sprintf("mustGetEnv: %v", err))
125         }
126         return env
127 }
128
129 // goListDriver uses the go list command to interpret the patterns and produce
130 // the build system package structure.
131 // See driver for more details.
132 func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
133         // Make sure that any asynchronous go commands are killed when we return.
134         parentCtx := cfg.Context
135         if parentCtx == nil {
136                 parentCtx = context.Background()
137         }
138         ctx, cancel := context.WithCancel(parentCtx)
139         defer cancel()
140
141         response := newDeduper()
142
143         state := &golistState{
144                 cfg:        cfg,
145                 ctx:        ctx,
146                 vendorDirs: map[string]bool{},
147         }
148
149         // Fill in response.Sizes asynchronously if necessary.
150         var sizeserr error
151         var sizeswg sync.WaitGroup
152         if cfg.Mode&NeedTypesSizes != 0 || cfg.Mode&NeedTypes != 0 {
153                 sizeswg.Add(1)
154                 go func() {
155                         var sizes types.Sizes
156                         sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, state.cfgInvocation(), cfg.gocmdRunner)
157                         // types.SizesFor always returns nil or a *types.StdSizes.
158                         response.dr.Sizes, _ = sizes.(*types.StdSizes)
159                         sizeswg.Done()
160                 }()
161         }
162
163         // Determine files requested in contains patterns
164         var containFiles []string
165         restPatterns := make([]string, 0, len(patterns))
166         // Extract file= and other [querytype]= patterns. Report an error if querytype
167         // doesn't exist.
168 extractQueries:
169         for _, pattern := range patterns {
170                 eqidx := strings.Index(pattern, "=")
171                 if eqidx < 0 {
172                         restPatterns = append(restPatterns, pattern)
173                 } else {
174                         query, value := pattern[:eqidx], pattern[eqidx+len("="):]
175                         switch query {
176                         case "file":
177                                 containFiles = append(containFiles, value)
178                         case "pattern":
179                                 restPatterns = append(restPatterns, value)
180                         case "": // not a reserved query
181                                 restPatterns = append(restPatterns, pattern)
182                         default:
183                                 for _, rune := range query {
184                                         if rune < 'a' || rune > 'z' { // not a reserved query
185                                                 restPatterns = append(restPatterns, pattern)
186                                                 continue extractQueries
187                                         }
188                                 }
189                                 // Reject all other patterns containing "="
190                                 return nil, fmt.Errorf("invalid query type %q in query pattern %q", query, pattern)
191                         }
192                 }
193         }
194
195         // See if we have any patterns to pass through to go list. Zero initial
196         // patterns also requires a go list call, since it's the equivalent of
197         // ".".
198         if len(restPatterns) > 0 || len(patterns) == 0 {
199                 dr, err := state.createDriverResponse(restPatterns...)
200                 if err != nil {
201                         return nil, err
202                 }
203                 response.addAll(dr)
204         }
205
206         if len(containFiles) != 0 {
207                 if err := state.runContainsQueries(response, containFiles); err != nil {
208                         return nil, err
209                 }
210         }
211
212         // Only use go/packages' overlay processing if we're using a Go version
213         // below 1.16. Otherwise, go list handles it.
214         if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 {
215                 modifiedPkgs, needPkgs, err := state.processGolistOverlay(response)
216                 if err != nil {
217                         return nil, err
218                 }
219
220                 var containsCandidates []string
221                 if len(containFiles) > 0 {
222                         containsCandidates = append(containsCandidates, modifiedPkgs...)
223                         containsCandidates = append(containsCandidates, needPkgs...)
224                 }
225                 if err := state.addNeededOverlayPackages(response, needPkgs); err != nil {
226                         return nil, err
227                 }
228                 // Check candidate packages for containFiles.
229                 if len(containFiles) > 0 {
230                         for _, id := range containsCandidates {
231                                 pkg, ok := response.seenPackages[id]
232                                 if !ok {
233                                         response.addPackage(&Package{
234                                                 ID: id,
235                                                 Errors: []Error{{
236                                                         Kind: ListError,
237                                                         Msg:  fmt.Sprintf("package %s expected but not seen", id),
238                                                 }},
239                                         })
240                                         continue
241                                 }
242                                 for _, f := range containFiles {
243                                         for _, g := range pkg.GoFiles {
244                                                 if sameFile(f, g) {
245                                                         response.addRoot(id)
246                                                 }
247                                         }
248                                 }
249                         }
250                 }
251                 // Add root for any package that matches a pattern. This applies only to
252                 // packages that are modified by overlays, since they are not added as
253                 // roots automatically.
254                 for _, pattern := range restPatterns {
255                         match := matchPattern(pattern)
256                         for _, pkgID := range modifiedPkgs {
257                                 pkg, ok := response.seenPackages[pkgID]
258                                 if !ok {
259                                         continue
260                                 }
261                                 if match(pkg.PkgPath) {
262                                         response.addRoot(pkg.ID)
263                                 }
264                         }
265                 }
266         }
267
268         sizeswg.Wait()
269         if sizeserr != nil {
270                 return nil, sizeserr
271         }
272         return response.dr, nil
273 }
274
275 func (state *golistState) addNeededOverlayPackages(response *responseDeduper, pkgs []string) error {
276         if len(pkgs) == 0 {
277                 return nil
278         }
279         dr, err := state.createDriverResponse(pkgs...)
280         if err != nil {
281                 return err
282         }
283         for _, pkg := range dr.Packages {
284                 response.addPackage(pkg)
285         }
286         _, needPkgs, err := state.processGolistOverlay(response)
287         if err != nil {
288                 return err
289         }
290         return state.addNeededOverlayPackages(response, needPkgs)
291 }
292
293 func (state *golistState) runContainsQueries(response *responseDeduper, queries []string) error {
294         for _, query := range queries {
295                 // TODO(matloob): Do only one query per directory.
296                 fdir := filepath.Dir(query)
297                 // Pass absolute path of directory to go list so that it knows to treat it as a directory,
298                 // not a package path.
299                 pattern, err := filepath.Abs(fdir)
300                 if err != nil {
301                         return fmt.Errorf("could not determine absolute path of file= query path %q: %v", query, err)
302                 }
303                 dirResponse, err := state.createDriverResponse(pattern)
304
305                 // If there was an error loading the package, or the package is returned
306                 // with errors, try to load the file as an ad-hoc package.
307                 // Usually the error will appear in a returned package, but may not if we're
308                 // in module mode and the ad-hoc is located outside a module.
309                 if err != nil || len(dirResponse.Packages) == 1 && len(dirResponse.Packages[0].GoFiles) == 0 &&
310                         len(dirResponse.Packages[0].Errors) == 1 {
311                         var queryErr error
312                         if dirResponse, queryErr = state.adhocPackage(pattern, query); queryErr != nil {
313                                 return err // return the original error
314                         }
315                 }
316                 isRoot := make(map[string]bool, len(dirResponse.Roots))
317                 for _, root := range dirResponse.Roots {
318                         isRoot[root] = true
319                 }
320                 for _, pkg := range dirResponse.Packages {
321                         // Add any new packages to the main set
322                         // We don't bother to filter packages that will be dropped by the changes of roots,
323                         // that will happen anyway during graph construction outside this function.
324                         // Over-reporting packages is not a problem.
325                         response.addPackage(pkg)
326                         // if the package was not a root one, it cannot have the file
327                         if !isRoot[pkg.ID] {
328                                 continue
329                         }
330                         for _, pkgFile := range pkg.GoFiles {
331                                 if filepath.Base(query) == filepath.Base(pkgFile) {
332                                         response.addRoot(pkg.ID)
333                                         break
334                                 }
335                         }
336                 }
337         }
338         return nil
339 }
340
341 // adhocPackage attempts to load or construct an ad-hoc package for a given
342 // query, if the original call to the driver produced inadequate results.
343 func (state *golistState) adhocPackage(pattern, query string) (*driverResponse, error) {
344         response, err := state.createDriverResponse(query)
345         if err != nil {
346                 return nil, err
347         }
348         // If we get nothing back from `go list`,
349         // try to make this file into its own ad-hoc package.
350         // TODO(rstambler): Should this check against the original response?
351         if len(response.Packages) == 0 {
352                 response.Packages = append(response.Packages, &Package{
353                         ID:              "command-line-arguments",
354                         PkgPath:         query,
355                         GoFiles:         []string{query},
356                         CompiledGoFiles: []string{query},
357                         Imports:         make(map[string]*Package),
358                 })
359                 response.Roots = append(response.Roots, "command-line-arguments")
360         }
361         // Handle special cases.
362         if len(response.Packages) == 1 {
363                 // golang/go#33482: If this is a file= query for ad-hoc packages where
364                 // the file only exists on an overlay, and exists outside of a module,
365                 // add the file to the package and remove the errors.
366                 if response.Packages[0].ID == "command-line-arguments" ||
367                         filepath.ToSlash(response.Packages[0].PkgPath) == filepath.ToSlash(query) {
368                         if len(response.Packages[0].GoFiles) == 0 {
369                                 filename := filepath.Join(pattern, filepath.Base(query)) // avoid recomputing abspath
370                                 // TODO(matloob): check if the file is outside of a root dir?
371                                 for path := range state.cfg.Overlay {
372                                         if path == filename {
373                                                 response.Packages[0].Errors = nil
374                                                 response.Packages[0].GoFiles = []string{path}
375                                                 response.Packages[0].CompiledGoFiles = []string{path}
376                                         }
377                                 }
378                         }
379                 }
380         }
381         return response, nil
382 }
383
384 // Fields must match go list;
385 // see $GOROOT/src/cmd/go/internal/load/pkg.go.
386 type jsonPackage struct {
387         ImportPath        string
388         Dir               string
389         Name              string
390         Export            string
391         GoFiles           []string
392         CompiledGoFiles   []string
393         IgnoredGoFiles    []string
394         IgnoredOtherFiles []string
395         CFiles            []string
396         CgoFiles          []string
397         CXXFiles          []string
398         MFiles            []string
399         HFiles            []string
400         FFiles            []string
401         SFiles            []string
402         SwigFiles         []string
403         SwigCXXFiles      []string
404         SysoFiles         []string
405         Imports           []string
406         ImportMap         map[string]string
407         Deps              []string
408         Module            *Module
409         TestGoFiles       []string
410         TestImports       []string
411         XTestGoFiles      []string
412         XTestImports      []string
413         ForTest           string // q in a "p [q.test]" package, else ""
414         DepOnly           bool
415
416         Error *jsonPackageError
417 }
418
419 type jsonPackageError struct {
420         ImportStack []string
421         Pos         string
422         Err         string
423 }
424
425 func otherFiles(p *jsonPackage) [][]string {
426         return [][]string{p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.SwigFiles, p.SwigCXXFiles, p.SysoFiles}
427 }
428
429 // createDriverResponse uses the "go list" command to expand the pattern
430 // words and return a response for the specified packages.
431 func (state *golistState) createDriverResponse(words ...string) (*driverResponse, error) {
432         // go list uses the following identifiers in ImportPath and Imports:
433         //
434         //      "p"                     -- importable package or main (command)
435         //      "q.test"                -- q's test executable
436         //      "p [q.test]"            -- variant of p as built for q's test executable
437         //      "q_test [q.test]"       -- q's external test package
438         //
439         // The packages p that are built differently for a test q.test
440         // are q itself, plus any helpers used by the external test q_test,
441         // typically including "testing" and all its dependencies.
442
443         // Run "go list" for complete
444         // information on the specified packages.
445         buf, err := state.invokeGo("list", golistargs(state.cfg, words)...)
446         if err != nil {
447                 return nil, err
448         }
449         seen := make(map[string]*jsonPackage)
450         pkgs := make(map[string]*Package)
451         additionalErrors := make(map[string][]Error)
452         // Decode the JSON and convert it to Package form.
453         var response driverResponse
454         for dec := json.NewDecoder(buf); dec.More(); {
455                 p := new(jsonPackage)
456                 if err := dec.Decode(p); err != nil {
457                         return nil, fmt.Errorf("JSON decoding failed: %v", err)
458                 }
459
460                 if p.ImportPath == "" {
461                         // The documentation for go list says that “[e]rroneous packages will have
462                         // a non-empty ImportPath”. If for some reason it comes back empty, we
463                         // prefer to error out rather than silently discarding data or handing
464                         // back a package without any way to refer to it.
465                         if p.Error != nil {
466                                 return nil, Error{
467                                         Pos: p.Error.Pos,
468                                         Msg: p.Error.Err,
469                                 }
470                         }
471                         return nil, fmt.Errorf("package missing import path: %+v", p)
472                 }
473
474                 // Work around https://golang.org/issue/33157:
475                 // go list -e, when given an absolute path, will find the package contained at
476                 // that directory. But when no package exists there, it will return a fake package
477                 // with an error and the ImportPath set to the absolute path provided to go list.
478                 // Try to convert that absolute path to what its package path would be if it's
479                 // contained in a known module or GOPATH entry. This will allow the package to be
480                 // properly "reclaimed" when overlays are processed.
481                 if filepath.IsAbs(p.ImportPath) && p.Error != nil {
482                         pkgPath, ok, err := state.getPkgPath(p.ImportPath)
483                         if err != nil {
484                                 return nil, err
485                         }
486                         if ok {
487                                 p.ImportPath = pkgPath
488                         }
489                 }
490
491                 if old, found := seen[p.ImportPath]; found {
492                         // If one version of the package has an error, and the other doesn't, assume
493                         // that this is a case where go list is reporting a fake dependency variant
494                         // of the imported package: When a package tries to invalidly import another
495                         // package, go list emits a variant of the imported package (with the same
496                         // import path, but with an error on it, and the package will have a
497                         // DepError set on it). An example of when this can happen is for imports of
498                         // main packages: main packages can not be imported, but they may be
499                         // separately matched and listed by another pattern.
500                         // See golang.org/issue/36188 for more details.
501
502                         // The plan is that eventually, hopefully in Go 1.15, the error will be
503                         // reported on the importing package rather than the duplicate "fake"
504                         // version of the imported package. Once all supported versions of Go
505                         // have the new behavior this logic can be deleted.
506                         // TODO(matloob): delete the workaround logic once all supported versions of
507                         // Go return the errors on the proper package.
508
509                         // There should be exactly one version of a package that doesn't have an
510                         // error.
511                         if old.Error == nil && p.Error == nil {
512                                 if !reflect.DeepEqual(p, old) {
513                                         return nil, fmt.Errorf("internal error: go list gives conflicting information for package %v", p.ImportPath)
514                                 }
515                                 continue
516                         }
517
518                         // Determine if this package's error needs to be bubbled up.
519                         // This is a hack, and we expect for go list to eventually set the error
520                         // on the package.
521                         if old.Error != nil {
522                                 var errkind string
523                                 if strings.Contains(old.Error.Err, "not an importable package") {
524                                         errkind = "not an importable package"
525                                 } else if strings.Contains(old.Error.Err, "use of internal package") && strings.Contains(old.Error.Err, "not allowed") {
526                                         errkind = "use of internal package not allowed"
527                                 }
528                                 if errkind != "" {
529                                         if len(old.Error.ImportStack) < 1 {
530                                                 return nil, fmt.Errorf(`internal error: go list gave a %q error with empty import stack`, errkind)
531                                         }
532                                         importingPkg := old.Error.ImportStack[len(old.Error.ImportStack)-1]
533                                         if importingPkg == old.ImportPath {
534                                                 // Using an older version of Go which put this package itself on top of import
535                                                 // stack, instead of the importer. Look for importer in second from top
536                                                 // position.
537                                                 if len(old.Error.ImportStack) < 2 {
538                                                         return nil, fmt.Errorf(`internal error: go list gave a %q error with an import stack without importing package`, errkind)
539                                                 }
540                                                 importingPkg = old.Error.ImportStack[len(old.Error.ImportStack)-2]
541                                         }
542                                         additionalErrors[importingPkg] = append(additionalErrors[importingPkg], Error{
543                                                 Pos:  old.Error.Pos,
544                                                 Msg:  old.Error.Err,
545                                                 Kind: ListError,
546                                         })
547                                 }
548                         }
549
550                         // Make sure that if there's a version of the package without an error,
551                         // that's the one reported to the user.
552                         if old.Error == nil {
553                                 continue
554                         }
555
556                         // This package will replace the old one at the end of the loop.
557                 }
558                 seen[p.ImportPath] = p
559
560                 pkg := &Package{
561                         Name:            p.Name,
562                         ID:              p.ImportPath,
563                         GoFiles:         absJoin(p.Dir, p.GoFiles, p.CgoFiles),
564                         CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles),
565                         OtherFiles:      absJoin(p.Dir, otherFiles(p)...),
566                         IgnoredFiles:    absJoin(p.Dir, p.IgnoredGoFiles, p.IgnoredOtherFiles),
567                         forTest:         p.ForTest,
568                         Module:          p.Module,
569                 }
570
571                 if (state.cfg.Mode&typecheckCgo) != 0 && len(p.CgoFiles) != 0 {
572                         if len(p.CompiledGoFiles) > len(p.GoFiles) {
573                                 // We need the cgo definitions, which are in the first
574                                 // CompiledGoFile after the non-cgo ones. This is a hack but there
575                                 // isn't currently a better way to find it. We also need the pure
576                                 // Go files and unprocessed cgo files, all of which are already
577                                 // in pkg.GoFiles.
578                                 cgoTypes := p.CompiledGoFiles[len(p.GoFiles)]
579                                 pkg.CompiledGoFiles = append([]string{cgoTypes}, pkg.GoFiles...)
580                         } else {
581                                 // golang/go#38990: go list silently fails to do cgo processing
582                                 pkg.CompiledGoFiles = nil
583                                 pkg.Errors = append(pkg.Errors, Error{
584                                         Msg:  "go list failed to return CompiledGoFiles; https://golang.org/issue/38990?",
585                                         Kind: ListError,
586                                 })
587                         }
588                 }
589
590                 // Work around https://golang.org/issue/28749:
591                 // cmd/go puts assembly, C, and C++ files in CompiledGoFiles.
592                 // Filter out any elements of CompiledGoFiles that are also in OtherFiles.
593                 // We have to keep this workaround in place until go1.12 is a distant memory.
594                 if len(pkg.OtherFiles) > 0 {
595                         other := make(map[string]bool, len(pkg.OtherFiles))
596                         for _, f := range pkg.OtherFiles {
597                                 other[f] = true
598                         }
599
600                         out := pkg.CompiledGoFiles[:0]
601                         for _, f := range pkg.CompiledGoFiles {
602                                 if other[f] {
603                                         continue
604                                 }
605                                 out = append(out, f)
606                         }
607                         pkg.CompiledGoFiles = out
608                 }
609
610                 // Extract the PkgPath from the package's ID.
611                 if i := strings.IndexByte(pkg.ID, ' '); i >= 0 {
612                         pkg.PkgPath = pkg.ID[:i]
613                 } else {
614                         pkg.PkgPath = pkg.ID
615                 }
616
617                 if pkg.PkgPath == "unsafe" {
618                         pkg.GoFiles = nil // ignore fake unsafe.go file
619                 }
620
621                 // Assume go list emits only absolute paths for Dir.
622                 if p.Dir != "" && !filepath.IsAbs(p.Dir) {
623                         log.Fatalf("internal error: go list returned non-absolute Package.Dir: %s", p.Dir)
624                 }
625
626                 if p.Export != "" && !filepath.IsAbs(p.Export) {
627                         pkg.ExportFile = filepath.Join(p.Dir, p.Export)
628                 } else {
629                         pkg.ExportFile = p.Export
630                 }
631
632                 // imports
633                 //
634                 // Imports contains the IDs of all imported packages.
635                 // ImportsMap records (path, ID) only where they differ.
636                 ids := make(map[string]bool)
637                 for _, id := range p.Imports {
638                         ids[id] = true
639                 }
640                 pkg.Imports = make(map[string]*Package)
641                 for path, id := range p.ImportMap {
642                         pkg.Imports[path] = &Package{ID: id} // non-identity import
643                         delete(ids, id)
644                 }
645                 for id := range ids {
646                         if id == "C" {
647                                 continue
648                         }
649
650                         pkg.Imports[id] = &Package{ID: id} // identity import
651                 }
652                 if !p.DepOnly {
653                         response.Roots = append(response.Roots, pkg.ID)
654                 }
655
656                 // Work around for pre-go.1.11 versions of go list.
657                 // TODO(matloob): they should be handled by the fallback.
658                 // Can we delete this?
659                 if len(pkg.CompiledGoFiles) == 0 {
660                         pkg.CompiledGoFiles = pkg.GoFiles
661                 }
662
663                 // Temporary work-around for golang/go#39986. Parse filenames out of
664                 // error messages. This happens if there are unrecoverable syntax
665                 // errors in the source, so we can't match on a specific error message.
666                 if err := p.Error; err != nil && state.shouldAddFilenameFromError(p) {
667                         addFilenameFromPos := func(pos string) bool {
668                                 split := strings.Split(pos, ":")
669                                 if len(split) < 1 {
670                                         return false
671                                 }
672                                 filename := strings.TrimSpace(split[0])
673                                 if filename == "" {
674                                         return false
675                                 }
676                                 if !filepath.IsAbs(filename) {
677                                         filename = filepath.Join(state.cfg.Dir, filename)
678                                 }
679                                 info, _ := os.Stat(filename)
680                                 if info == nil {
681                                         return false
682                                 }
683                                 pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, filename)
684                                 pkg.GoFiles = append(pkg.GoFiles, filename)
685                                 return true
686                         }
687                         found := addFilenameFromPos(err.Pos)
688                         // In some cases, go list only reports the error position in the
689                         // error text, not the error position. One such case is when the
690                         // file's package name is a keyword (see golang.org/issue/39763).
691                         if !found {
692                                 addFilenameFromPos(err.Err)
693                         }
694                 }
695
696                 if p.Error != nil {
697                         msg := strings.TrimSpace(p.Error.Err) // Trim to work around golang.org/issue/32363.
698                         // Address golang.org/issue/35964 by appending import stack to error message.
699                         if msg == "import cycle not allowed" && len(p.Error.ImportStack) != 0 {
700                                 msg += fmt.Sprintf(": import stack: %v", p.Error.ImportStack)
701                         }
702                         pkg.Errors = append(pkg.Errors, Error{
703                                 Pos:  p.Error.Pos,
704                                 Msg:  msg,
705                                 Kind: ListError,
706                         })
707                 }
708
709                 pkgs[pkg.ID] = pkg
710         }
711
712         for id, errs := range additionalErrors {
713                 if p, ok := pkgs[id]; ok {
714                         p.Errors = append(p.Errors, errs...)
715                 }
716         }
717         for _, pkg := range pkgs {
718                 response.Packages = append(response.Packages, pkg)
719         }
720         sort.Slice(response.Packages, func(i, j int) bool { return response.Packages[i].ID < response.Packages[j].ID })
721
722         return &response, nil
723 }
724
725 func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
726         if len(p.GoFiles) > 0 || len(p.CompiledGoFiles) > 0 {
727                 return false
728         }
729
730         goV, err := state.getGoVersion()
731         if err != nil {
732                 return false
733         }
734
735         // On Go 1.14 and earlier, only add filenames from errors if the import stack is empty.
736         // The import stack behaves differently for these versions than newer Go versions.
737         if goV < 15 {
738                 return len(p.Error.ImportStack) == 0
739         }
740
741         // On Go 1.15 and later, only parse filenames out of error if there's no import stack,
742         // or the current package is at the top of the import stack. This is not guaranteed
743         // to work perfectly, but should avoid some cases where files in errors don't belong to this
744         // package.
745         return len(p.Error.ImportStack) == 0 || p.Error.ImportStack[len(p.Error.ImportStack)-1] == p.ImportPath
746 }
747
748 func (state *golistState) getGoVersion() (int, error) {
749         state.goVersionOnce.Do(func() {
750                 state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner)
751         })
752         return state.goVersion, state.goVersionError
753 }
754
755 // getPkgPath finds the package path of a directory if it's relative to a root
756 // directory.
757 func (state *golistState) getPkgPath(dir string) (string, bool, error) {
758         absDir, err := filepath.Abs(dir)
759         if err != nil {
760                 return "", false, err
761         }
762         roots, err := state.determineRootDirs()
763         if err != nil {
764                 return "", false, err
765         }
766
767         for rdir, rpath := range roots {
768                 // Make sure that the directory is in the module,
769                 // to avoid creating a path relative to another module.
770                 if !strings.HasPrefix(absDir, rdir) {
771                         continue
772                 }
773                 // TODO(matloob): This doesn't properly handle symlinks.
774                 r, err := filepath.Rel(rdir, dir)
775                 if err != nil {
776                         continue
777                 }
778                 if rpath != "" {
779                         // We choose only one root even though the directory even it can belong in multiple modules
780                         // or GOPATH entries. This is okay because we only need to work with absolute dirs when a
781                         // file is missing from disk, for instance when gopls calls go/packages in an overlay.
782                         // Once the file is saved, gopls, or the next invocation of the tool will get the correct
783                         // result straight from golist.
784                         // TODO(matloob): Implement module tiebreaking?
785                         return path.Join(rpath, filepath.ToSlash(r)), true, nil
786                 }
787                 return filepath.ToSlash(r), true, nil
788         }
789         return "", false, nil
790 }
791
792 // absJoin absolutizes and flattens the lists of files.
793 func absJoin(dir string, fileses ...[]string) (res []string) {
794         for _, files := range fileses {
795                 for _, file := range files {
796                         if !filepath.IsAbs(file) {
797                                 file = filepath.Join(dir, file)
798                         }
799                         res = append(res, file)
800                 }
801         }
802         return res
803 }
804
805 func golistargs(cfg *Config, words []string) []string {
806         const findFlags = NeedImports | NeedTypes | NeedSyntax | NeedTypesInfo
807         fullargs := []string{
808                 "-e", "-json",
809                 fmt.Sprintf("-compiled=%t", cfg.Mode&(NeedCompiledGoFiles|NeedSyntax|NeedTypes|NeedTypesInfo|NeedTypesSizes) != 0),
810                 fmt.Sprintf("-test=%t", cfg.Tests),
811                 fmt.Sprintf("-export=%t", usesExportData(cfg)),
812                 fmt.Sprintf("-deps=%t", cfg.Mode&NeedImports != 0),
813                 // go list doesn't let you pass -test and -find together,
814                 // probably because you'd just get the TestMain.
815                 fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0),
816         }
817         fullargs = append(fullargs, cfg.BuildFlags...)
818         fullargs = append(fullargs, "--")
819         fullargs = append(fullargs, words...)
820         return fullargs
821 }
822
823 // cfgInvocation returns an Invocation that reflects cfg's settings.
824 func (state *golistState) cfgInvocation() gocommand.Invocation {
825         cfg := state.cfg
826         return gocommand.Invocation{
827                 BuildFlags: cfg.BuildFlags,
828                 ModFile:    cfg.modFile,
829                 ModFlag:    cfg.modFlag,
830                 Env:        cfg.Env,
831                 Logf:       cfg.Logf,
832                 WorkingDir: cfg.Dir,
833         }
834 }
835
836 // invokeGo returns the stdout of a go command invocation.
837 func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, error) {
838         cfg := state.cfg
839
840         inv := state.cfgInvocation()
841
842         // For Go versions 1.16 and above, `go list` accepts overlays directly via
843         // the -overlay flag. Set it, if it's available.
844         //
845         // The check for "list" is not necessarily required, but we should avoid
846         // getting the go version if possible.
847         if verb == "list" {
848                 goVersion, err := state.getGoVersion()
849                 if err != nil {
850                         return nil, err
851                 }
852                 if goVersion >= 16 {
853                         filename, cleanup, err := state.writeOverlays()
854                         if err != nil {
855                                 return nil, err
856                         }
857                         defer cleanup()
858                         inv.Overlay = filename
859                 }
860         }
861         inv.Verb = verb
862         inv.Args = args
863         gocmdRunner := cfg.gocmdRunner
864         if gocmdRunner == nil {
865                 gocmdRunner = &gocommand.Runner{}
866         }
867         stdout, stderr, _, err := gocmdRunner.RunRaw(cfg.Context, inv)
868         if err != nil {
869                 // Check for 'go' executable not being found.
870                 if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound {
871                         return nil, fmt.Errorf("'go list' driver requires 'go', but %s", exec.ErrNotFound)
872                 }
873
874                 exitErr, ok := err.(*exec.ExitError)
875                 if !ok {
876                         // Catastrophic error:
877                         // - context cancellation
878                         return nil, xerrors.Errorf("couldn't run 'go': %w", err)
879                 }
880
881                 // Old go version?
882                 if strings.Contains(stderr.String(), "flag provided but not defined") {
883                         return nil, goTooOldError{fmt.Errorf("unsupported version of go: %s: %s", exitErr, stderr)}
884                 }
885
886                 // Related to #24854
887                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "unexpected directory layout") {
888                         return nil, fmt.Errorf("%s", stderr.String())
889                 }
890
891                 // Is there an error running the C compiler in cgo? This will be reported in the "Error" field
892                 // and should be suppressed by go list -e.
893                 //
894                 // This condition is not perfect yet because the error message can include other error messages than runtime/cgo.
895                 isPkgPathRune := func(r rune) bool {
896                         // From https://golang.org/ref/spec#Import_declarations:
897                         //    Implementation restriction: A compiler may restrict ImportPaths to non-empty strings
898                         //    using only characters belonging to Unicode's L, M, N, P, and S general categories
899                         //    (the Graphic characters without spaces) and may also exclude the
900                         //    characters !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character U+FFFD.
901                         return unicode.IsOneOf([]*unicode.RangeTable{unicode.L, unicode.M, unicode.N, unicode.P, unicode.S}, r) &&
902                                 !strings.ContainsRune("!\"#$%&'()*,:;<=>?[\\]^`{|}\uFFFD", r)
903                 }
904                 if len(stderr.String()) > 0 && strings.HasPrefix(stderr.String(), "# ") {
905                         msg := stderr.String()[len("# "):]
906                         if strings.HasPrefix(strings.TrimLeftFunc(msg, isPkgPathRune), "\n") {
907                                 return stdout, nil
908                         }
909                         // Treat pkg-config errors as a special case (golang.org/issue/36770).
910                         if strings.HasPrefix(msg, "pkg-config") {
911                                 return stdout, nil
912                         }
913                 }
914
915                 // This error only appears in stderr. See golang.org/cl/166398 for a fix in go list to show
916                 // the error in the Err section of stdout in case -e option is provided.
917                 // This fix is provided for backwards compatibility.
918                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must be .go files") {
919                         output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
920                                 strings.Trim(stderr.String(), "\n"))
921                         return bytes.NewBufferString(output), nil
922                 }
923
924                 // Similar to the previous error, but currently lacks a fix in Go.
925                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "named files must all be in one directory") {
926                         output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
927                                 strings.Trim(stderr.String(), "\n"))
928                         return bytes.NewBufferString(output), nil
929                 }
930
931                 // Backwards compatibility for Go 1.11 because 1.12 and 1.13 put the directory in the ImportPath.
932                 // If the package doesn't exist, put the absolute path of the directory into the error message,
933                 // as Go 1.13 list does.
934                 const noSuchDirectory = "no such directory"
935                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), noSuchDirectory) {
936                         errstr := stderr.String()
937                         abspath := strings.TrimSpace(errstr[strings.Index(errstr, noSuchDirectory)+len(noSuchDirectory):])
938                         output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
939                                 abspath, strings.Trim(stderr.String(), "\n"))
940                         return bytes.NewBufferString(output), nil
941                 }
942
943                 // Workaround for #29280: go list -e has incorrect behavior when an ad-hoc package doesn't exist.
944                 // Note that the error message we look for in this case is different that the one looked for above.
945                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no such file or directory") {
946                         output := fmt.Sprintf(`{"ImportPath": "command-line-arguments","Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
947                                 strings.Trim(stderr.String(), "\n"))
948                         return bytes.NewBufferString(output), nil
949                 }
950
951                 // Workaround for #34273. go list -e with GO111MODULE=on has incorrect behavior when listing a
952                 // directory outside any module.
953                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "outside available modules") {
954                         output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
955                                 // TODO(matloob): command-line-arguments isn't correct here.
956                                 "command-line-arguments", strings.Trim(stderr.String(), "\n"))
957                         return bytes.NewBufferString(output), nil
958                 }
959
960                 // Another variation of the previous error
961                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "outside module root") {
962                         output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
963                                 // TODO(matloob): command-line-arguments isn't correct here.
964                                 "command-line-arguments", strings.Trim(stderr.String(), "\n"))
965                         return bytes.NewBufferString(output), nil
966                 }
967
968                 // Workaround for an instance of golang.org/issue/26755: go list -e  will return a non-zero exit
969                 // status if there's a dependency on a package that doesn't exist. But it should return
970                 // a zero exit status and set an error on that package.
971                 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no Go files in") {
972                         // Don't clobber stdout if `go list` actually returned something.
973                         if len(stdout.String()) > 0 {
974                                 return stdout, nil
975                         }
976                         // try to extract package name from string
977                         stderrStr := stderr.String()
978                         var importPath string
979                         colon := strings.Index(stderrStr, ":")
980                         if colon > 0 && strings.HasPrefix(stderrStr, "go build ") {
981                                 importPath = stderrStr[len("go build "):colon]
982                         }
983                         output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`,
984                                 importPath, strings.Trim(stderrStr, "\n"))
985                         return bytes.NewBufferString(output), nil
986                 }
987
988                 // Export mode entails a build.
989                 // If that build fails, errors appear on stderr
990                 // (despite the -e flag) and the Export field is blank.
991                 // Do not fail in that case.
992                 // The same is true if an ad-hoc package given to go list doesn't exist.
993                 // TODO(matloob): Remove these once we can depend on go list to exit with a zero status with -e even when
994                 // packages don't exist or a build fails.
995                 if !usesExportData(cfg) && !containsGoFile(args) {
996                         return nil, fmt.Errorf("go %v: %s: %s", args, exitErr, stderr)
997                 }
998         }
999         return stdout, nil
1000 }
1001
1002 // OverlayJSON is the format overlay files are expected to be in.
1003 // The Replace map maps from overlaid paths to replacement paths:
1004 // the Go command will forward all reads trying to open
1005 // each overlaid path to its replacement path, or consider the overlaid
1006 // path not to exist if the replacement path is empty.
1007 //
1008 // From golang/go#39958.
1009 type OverlayJSON struct {
1010         Replace map[string]string `json:"replace,omitempty"`
1011 }
1012
1013 // writeOverlays writes out files for go list's -overlay flag, as described
1014 // above.
1015 func (state *golistState) writeOverlays() (filename string, cleanup func(), err error) {
1016         // Do nothing if there are no overlays in the config.
1017         if len(state.cfg.Overlay) == 0 {
1018                 return "", func() {}, nil
1019         }
1020         dir, err := ioutil.TempDir("", "gopackages-*")
1021         if err != nil {
1022                 return "", nil, err
1023         }
1024         // The caller must clean up this directory, unless this function returns an
1025         // error.
1026         cleanup = func() {
1027                 os.RemoveAll(dir)
1028         }
1029         defer func() {
1030                 if err != nil {
1031                         cleanup()
1032                 }
1033         }()
1034         overlays := map[string]string{}
1035         for k, v := range state.cfg.Overlay {
1036                 // Create a unique filename for the overlaid files, to avoid
1037                 // creating nested directories.
1038                 noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "")
1039                 f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator))
1040                 if err != nil {
1041                         return "", func() {}, err
1042                 }
1043                 if _, err := f.Write(v); err != nil {
1044                         return "", func() {}, err
1045                 }
1046                 if err := f.Close(); err != nil {
1047                         return "", func() {}, err
1048                 }
1049                 overlays[k] = f.Name()
1050         }
1051         b, err := json.Marshal(OverlayJSON{Replace: overlays})
1052         if err != nil {
1053                 return "", func() {}, err
1054         }
1055         // Write out the overlay file that contains the filepath mappings.
1056         filename = filepath.Join(dir, "overlay.json")
1057         if err := ioutil.WriteFile(filename, b, 0665); err != nil {
1058                 return "", func() {}, err
1059         }
1060         return filename, cleanup, nil
1061 }
1062
1063 func containsGoFile(s []string) bool {
1064         for _, f := range s {
1065                 if strings.HasSuffix(f, ".go") {
1066                         return true
1067                 }
1068         }
1069         return false
1070 }
1071
1072 func cmdDebugStr(cmd *exec.Cmd, args ...string) string {
1073         env := make(map[string]string)
1074         for _, kv := range cmd.Env {
1075                 split := strings.Split(kv, "=")
1076                 k, v := split[0], split[1]
1077                 env[k] = v
1078         }
1079         var quotedArgs []string
1080         for _, arg := range args {
1081                 quotedArgs = append(quotedArgs, strconv.Quote(arg))
1082         }
1083
1084         return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %s", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["PWD"], strings.Join(quotedArgs, " "))
1085 }