//go:build ignore // Copyright 2024 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. // The cfg command prints the control-flow graph of the first function // or method whose name matches 'funcname' in the specified package. // // Usage: cfg package funcname // // Example: // // $ go build -o cfg ./go/cfg/main.go // $ cfg ./go/cfg stmt | dot -Tsvg > cfg.svg && open cfg.svg package main import ( "flag" "fmt" "go/ast" "log" "os" "golang.org/x/tools/go/cfg" "golang.org/x/tools/go/packages" ) func main() { flag.Parse() if len(flag.Args()) != 2 { log.Fatal("Usage: package funcname") } pattern, funcname := flag.Args()[0], flag.Args()[1] pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadSyntax}, pattern) if err != nil { log.Fatal(err) } if packages.PrintErrors(pkgs) > 0 { os.Exit(1) } for _, pkg := range pkgs { for _, f := range pkg.Syntax { for _, decl := range f.Decls { if decl, ok := decl.(*ast.FuncDecl); ok { if decl.Name.Name == funcname { g := cfg.New(decl.Body, mayReturn) fmt.Println(g.Dot(pkg.Fset)) os.Exit(0) } } } } } log.Fatalf("no function %q found in %s", funcname, pattern) } // A trivial mayReturn predicate that looks only at syntax, not types. func mayReturn(call *ast.CallExpr) bool { switch fun := call.Fun.(type) { case *ast.Ident: return fun.Name != "panic" case *ast.SelectorExpr: return fun.Sel.Name != "Fatal" } return true }