.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / cmd / callgraph / main.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/cmd/callgraph/main.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/cmd/callgraph/main.go
new file mode 100644 (file)
index 0000000..f74c278
--- /dev/null
@@ -0,0 +1,349 @@
+// 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.
+
+// callgraph: a tool for reporting the call graph of a Go program.
+// See Usage for details, or run with -help.
+package main // import "golang.org/x/tools/cmd/callgraph"
+
+// TODO(adonovan):
+//
+// Features:
+// - restrict graph to a single package
+// - output
+//   - functions reachable from root (use digraph tool?)
+//   - unreachable functions (use digraph tool?)
+//   - dynamic (runtime) types
+//   - indexed output (numbered nodes)
+//   - JSON output
+//   - additional template fields:
+//     callee file/line/col
+
+import (
+       "bufio"
+       "bytes"
+       "flag"
+       "fmt"
+       "go/build"
+       "go/token"
+       "io"
+       "log"
+       "os"
+       "runtime"
+       "text/template"
+
+       "golang.org/x/tools/go/buildutil"
+       "golang.org/x/tools/go/callgraph"
+       "golang.org/x/tools/go/callgraph/cha"
+       "golang.org/x/tools/go/callgraph/rta"
+       "golang.org/x/tools/go/callgraph/static"
+       "golang.org/x/tools/go/packages"
+       "golang.org/x/tools/go/pointer"
+       "golang.org/x/tools/go/ssa"
+       "golang.org/x/tools/go/ssa/ssautil"
+)
+
+// flags
+var (
+       algoFlag = flag.String("algo", "rta",
+               `Call graph construction algorithm (static, cha, rta, pta)`)
+
+       testFlag = flag.Bool("test", false,
+               "Loads test code (*_test.go) for imported packages")
+
+       formatFlag = flag.String("format",
+               "{{.Caller}}\t--{{.Dynamic}}-{{.Line}}:{{.Column}}-->\t{{.Callee}}",
+               "A template expression specifying how to format an edge")
+
+       ptalogFlag = flag.String("ptalog", "",
+               "Location of the points-to analysis log file, or empty to disable logging.")
+)
+
+func init() {
+       flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+}
+
+const Usage = `callgraph: display the call graph of a Go program.
+
+Usage:
+
+  callgraph [-algo=static|cha|rta|pta] [-test] [-format=...] package...
+
+Flags:
+
+-algo      Specifies the call-graph construction algorithm, one of:
+
+            static      static calls only (unsound)
+            cha         Class Hierarchy Analysis
+            rta         Rapid Type Analysis
+            pta         inclusion-based Points-To Analysis
+
+           The algorithms are ordered by increasing precision in their
+           treatment of dynamic calls (and thus also computational cost).
+           RTA and PTA require a whole program (main or test), and
+           include only functions reachable from main.
+
+-test      Include the package's tests in the analysis.
+
+-format    Specifies the format in which each call graph edge is displayed.
+           One of:
+
+            digraph     output suitable for input to
+                        golang.org/x/tools/cmd/digraph.
+            graphviz    output in AT&T GraphViz (.dot) format.
+
+           All other values are interpreted using text/template syntax.
+           The default value is:
+
+            {{.Caller}}\t--{{.Dynamic}}-{{.Line}}:{{.Column}}-->\t{{.Callee}}
+
+           The structure passed to the template is (effectively):
+
+                   type Edge struct {
+                           Caller      *ssa.Function // calling function
+                           Callee      *ssa.Function // called function
+
+                           // Call site:
+                           Filename    string // containing file
+                           Offset      int    // offset within file of '('
+                           Line        int    // line number
+                           Column      int    // column number of call
+                           Dynamic     string // "static" or "dynamic"
+                           Description string // e.g. "static method call"
+                   }
+
+           Caller and Callee are *ssa.Function values, which print as
+           "(*sync/atomic.Mutex).Lock", but other attributes may be
+           derived from them, e.g. Caller.Pkg.Pkg.Path yields the
+           import path of the enclosing package.  Consult the go/ssa
+           API documentation for details.
+
+Examples:
+
+  Show the call graph of the trivial web server application:
+
+    callgraph -format digraph $GOROOT/src/net/http/triv.go
+
+  Same, but show only the packages of each function:
+
+    callgraph -format '{{.Caller.Pkg.Pkg.Path}} -> {{.Callee.Pkg.Pkg.Path}}' \
+      $GOROOT/src/net/http/triv.go | sort | uniq
+
+  Show functions that make dynamic calls into the 'fmt' test package,
+  using the pointer analysis algorithm:
+
+    callgraph -format='{{.Caller}} -{{.Dynamic}}-> {{.Callee}}' -test -algo=pta fmt |
+      sed -ne 's/-dynamic-/--/p' |
+      sed -ne 's/-->.*fmt_test.*$//p' | sort | uniq
+
+  Show all functions directly called by the callgraph tool's main function:
+
+    callgraph -format=digraph golang.org/x/tools/cmd/callgraph |
+      digraph succs golang.org/x/tools/cmd/callgraph.main
+`
+
+func init() {
+       // If $GOMAXPROCS isn't set, use the full capacity of the machine.
+       // For small machines, use at least 4 threads.
+       if os.Getenv("GOMAXPROCS") == "" {
+               n := runtime.NumCPU()
+               if n < 4 {
+                       n = 4
+               }
+               runtime.GOMAXPROCS(n)
+       }
+}
+
+func main() {
+       flag.Parse()
+       if err := doCallgraph("", "", *algoFlag, *formatFlag, *testFlag, flag.Args()); err != nil {
+               fmt.Fprintf(os.Stderr, "callgraph: %s\n", err)
+               os.Exit(1)
+       }
+}
+
+var stdout io.Writer = os.Stdout
+
+func doCallgraph(dir, gopath, algo, format string, tests bool, args []string) error {
+       if len(args) == 0 {
+               fmt.Fprintln(os.Stderr, Usage)
+               return nil
+       }
+
+       cfg := &packages.Config{
+               Mode:  packages.LoadAllSyntax,
+               Tests: tests,
+               Dir:   dir,
+       }
+       if gopath != "" {
+               cfg.Env = append(os.Environ(), "GOPATH="+gopath) // to enable testing
+       }
+       initial, err := packages.Load(cfg, args...)
+       if err != nil {
+               return err
+       }
+       if packages.PrintErrors(initial) > 0 {
+               return fmt.Errorf("packages contain errors")
+       }
+
+       // Create and build SSA-form program representation.
+       prog, pkgs := ssautil.AllPackages(initial, 0)
+       prog.Build()
+
+       // -- call graph construction ------------------------------------------
+
+       var cg *callgraph.Graph
+
+       switch algo {
+       case "static":
+               cg = static.CallGraph(prog)
+
+       case "cha":
+               cg = cha.CallGraph(prog)
+
+       case "pta":
+               // Set up points-to analysis log file.
+               var ptalog io.Writer
+               if *ptalogFlag != "" {
+                       if f, err := os.Create(*ptalogFlag); err != nil {
+                               log.Fatalf("Failed to create PTA log file: %s", err)
+                       } else {
+                               buf := bufio.NewWriter(f)
+                               ptalog = buf
+                               defer func() {
+                                       if err := buf.Flush(); err != nil {
+                                               log.Printf("flush: %s", err)
+                                       }
+                                       if err := f.Close(); err != nil {
+                                               log.Printf("close: %s", err)
+                                       }
+                               }()
+                       }
+               }
+
+               mains, err := mainPackages(pkgs)
+               if err != nil {
+                       return err
+               }
+               config := &pointer.Config{
+                       Mains:          mains,
+                       BuildCallGraph: true,
+                       Log:            ptalog,
+               }
+               ptares, err := pointer.Analyze(config)
+               if err != nil {
+                       return err // internal error in pointer analysis
+               }
+               cg = ptares.CallGraph
+
+       case "rta":
+               mains, err := mainPackages(pkgs)
+               if err != nil {
+                       return err
+               }
+               var roots []*ssa.Function
+               for _, main := range mains {
+                       roots = append(roots, main.Func("init"), main.Func("main"))
+               }
+               rtares := rta.Analyze(roots, true)
+               cg = rtares.CallGraph
+
+               // NB: RTA gives us Reachable and RuntimeTypes too.
+
+       default:
+               return fmt.Errorf("unknown algorithm: %s", algo)
+       }
+
+       cg.DeleteSyntheticNodes()
+
+       // -- output------------------------------------------------------------
+
+       var before, after string
+
+       // Pre-canned formats.
+       switch format {
+       case "digraph":
+               format = `{{printf "%q %q" .Caller .Callee}}`
+
+       case "graphviz":
+               before = "digraph callgraph {\n"
+               after = "}\n"
+               format = `  {{printf "%q" .Caller}} -> {{printf "%q" .Callee}}`
+       }
+
+       tmpl, err := template.New("-format").Parse(format)
+       if err != nil {
+               return fmt.Errorf("invalid -format template: %v", err)
+       }
+
+       // Allocate these once, outside the traversal.
+       var buf bytes.Buffer
+       data := Edge{fset: prog.Fset}
+
+       fmt.Fprint(stdout, before)
+       if err := callgraph.GraphVisitEdges(cg, func(edge *callgraph.Edge) error {
+               data.position.Offset = -1
+               data.edge = edge
+               data.Caller = edge.Caller.Func
+               data.Callee = edge.Callee.Func
+
+               buf.Reset()
+               if err := tmpl.Execute(&buf, &data); err != nil {
+                       return err
+               }
+               stdout.Write(buf.Bytes())
+               if len := buf.Len(); len == 0 || buf.Bytes()[len-1] != '\n' {
+                       fmt.Fprintln(stdout)
+               }
+               return nil
+       }); err != nil {
+               return err
+       }
+       fmt.Fprint(stdout, after)
+       return nil
+}
+
+// mainPackages returns the main packages to analyze.
+// Each resulting package is named "main" and has a main function.
+func mainPackages(pkgs []*ssa.Package) ([]*ssa.Package, error) {
+       var mains []*ssa.Package
+       for _, p := range pkgs {
+               if p != nil && p.Pkg.Name() == "main" && p.Func("main") != nil {
+                       mains = append(mains, p)
+               }
+       }
+       if len(mains) == 0 {
+               return nil, fmt.Errorf("no main packages")
+       }
+       return mains, nil
+}
+
+type Edge struct {
+       Caller *ssa.Function
+       Callee *ssa.Function
+
+       edge     *callgraph.Edge
+       fset     *token.FileSet
+       position token.Position // initialized lazily
+}
+
+func (e *Edge) pos() *token.Position {
+       if e.position.Offset == -1 {
+               e.position = e.fset.Position(e.edge.Pos()) // called lazily
+       }
+       return &e.position
+}
+
+func (e *Edge) Filename() string { return e.pos().Filename }
+func (e *Edge) Column() int      { return e.pos().Column }
+func (e *Edge) Line() int        { return e.pos().Line }
+func (e *Edge) Offset() int      { return e.pos().Offset }
+
+func (e *Edge) Dynamic() string {
+       if e.edge.Site != nil && e.edge.Site.Common().StaticCallee() == nil {
+               return "dynamic"
+       }
+       return "static"
+}
+
+func (e *Edge) Description() string { return e.edge.Description() }