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