Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / refactor / importgraph / graph.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/refactor/importgraph/graph.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/refactor/importgraph/graph.go
new file mode 100644 (file)
index 0000000..d2d8f09
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package importgraph computes the forward and reverse import
+// dependency graphs for all packages in a Go workspace.
+package importgraph // import "golang.org/x/tools/refactor/importgraph"
+
+import (
+       "go/build"
+       "sync"
+
+       "golang.org/x/tools/go/buildutil"
+)
+
+// A Graph is an import dependency graph, either forward or reverse.
+//
+// The graph maps each node (a package import path) to the set of its
+// successors in the graph.  For a forward graph, this is the set of
+// imported packages (prerequisites); for a reverse graph, it is the set
+// of importing packages (clients).
+//
+// Graph construction inspects all imports in each package's directory,
+// including those in _test.go files, so the resulting graph may be cyclic.
+type Graph map[string]map[string]bool
+
+func (g Graph) addEdge(from, to string) {
+       edges := g[from]
+       if edges == nil {
+               edges = make(map[string]bool)
+               g[from] = edges
+       }
+       edges[to] = true
+}
+
+// Search returns all the nodes of the graph reachable from
+// any of the specified roots, by following edges forwards.
+// Relationally, this is the reflexive transitive closure.
+func (g Graph) Search(roots ...string) map[string]bool {
+       seen := make(map[string]bool)
+       var visit func(x string)
+       visit = func(x string) {
+               if !seen[x] {
+                       seen[x] = true
+                       for y := range g[x] {
+                               visit(y)
+                       }
+               }
+       }
+       for _, root := range roots {
+               visit(root)
+       }
+       return seen
+}
+
+// Build scans the specified Go workspace and builds the forward and
+// reverse import dependency graphs for all its packages.
+// It also returns a mapping from canonical import paths to errors for packages
+// whose loading was not entirely successful.
+// A package may appear in the graph and in the errors mapping.
+// All package paths are canonical and may contain "/vendor/".
+func Build(ctxt *build.Context) (forward, reverse Graph, errors map[string]error) {
+       type importEdge struct {
+               from, to string
+       }
+       type pathError struct {
+               path string
+               err  error
+       }
+
+       ch := make(chan interface{})
+
+       go func() {
+               sema := make(chan int, 20) // I/O concurrency limiting semaphore
+               var wg sync.WaitGroup
+               buildutil.ForEachPackage(ctxt, func(path string, err error) {
+                       if err != nil {
+                               ch <- pathError{path, err}
+                               return
+                       }
+
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+
+                               sema <- 1
+                               bp, err := ctxt.Import(path, "", 0)
+                               <-sema
+
+                               if err != nil {
+                                       if _, ok := err.(*build.NoGoError); ok {
+                                               // empty directory is not an error
+                                       } else {
+                                               ch <- pathError{path, err}
+                                       }
+                                       // Even in error cases, Import usually returns a package.
+                               }
+
+                               // absolutize resolves an import path relative
+                               // to the current package bp.
+                               // The absolute form may contain "vendor".
+                               //
+                               // The vendoring feature slows down Build by 3×.
+                               // Here are timings from a 1400 package workspace:
+                               //    1100ms: current code (with vendor check)
+                               //     880ms: with a nonblocking cache around ctxt.IsDir
+                               //     840ms: nonblocking cache with duplicate suppression
+                               //     340ms: original code (no vendor check)
+                               // TODO(adonovan): optimize, somehow.
+                               memo := make(map[string]string)
+                               absolutize := func(path string) string {
+                                       canon, ok := memo[path]
+                                       if !ok {
+                                               sema <- 1
+                                               bp2, _ := ctxt.Import(path, bp.Dir, build.FindOnly)
+                                               <-sema
+
+                                               if bp2 != nil {
+                                                       canon = bp2.ImportPath
+                                               } else {
+                                                       canon = path
+                                               }
+                                               memo[path] = canon
+                                       }
+                                       return canon
+                               }
+
+                               if bp != nil {
+                                       for _, imp := range bp.Imports {
+                                               ch <- importEdge{path, absolutize(imp)}
+                                       }
+                                       for _, imp := range bp.TestImports {
+                                               ch <- importEdge{path, absolutize(imp)}
+                                       }
+                                       for _, imp := range bp.XTestImports {
+                                               ch <- importEdge{path, absolutize(imp)}
+                                       }
+                               }
+
+                       }()
+               })
+               wg.Wait()
+               close(ch)
+       }()
+
+       forward = make(Graph)
+       reverse = make(Graph)
+
+       for e := range ch {
+               switch e := e.(type) {
+               case pathError:
+                       if errors == nil {
+                               errors = make(map[string]error)
+                       }
+                       errors[e.path] = e.err
+
+               case importEdge:
+                       if e.to == "C" {
+                               continue // "C" is fake
+                       }
+                       forward.addEdge(e.from, e.to)
+                       reverse.addEdge(e.to, e.from)
+               }
+       }
+
+       return forward, reverse, errors
+}