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