golang.org/x/tools@v0.21.0/go/cfg/main.go (about)

     1  //go:build ignore
     2  
     3  // Copyright 2024 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // The cfg command prints the control-flow graph of the first function
     8  // or method whose name matches 'funcname' in the specified package.
     9  //
    10  // Usage: cfg package funcname
    11  //
    12  // Example:
    13  //
    14  //	$ go build -o cfg ./go/cfg/main.go
    15  //	$ cfg ./go/cfg stmt | dot -Tsvg > cfg.svg && open cfg.svg
    16  package main
    17  
    18  import (
    19  	"flag"
    20  	"fmt"
    21  	"go/ast"
    22  	"log"
    23  	"os"
    24  
    25  	"golang.org/x/tools/go/cfg"
    26  	"golang.org/x/tools/go/packages"
    27  )
    28  
    29  func main() {
    30  	flag.Parse()
    31  	if len(flag.Args()) != 2 {
    32  		log.Fatal("Usage: package funcname")
    33  	}
    34  	pattern, funcname := flag.Args()[0], flag.Args()[1]
    35  	pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadSyntax}, pattern)
    36  	if err != nil {
    37  		log.Fatal(err)
    38  	}
    39  	if packages.PrintErrors(pkgs) > 0 {
    40  		os.Exit(1)
    41  	}
    42  	for _, pkg := range pkgs {
    43  		for _, f := range pkg.Syntax {
    44  			for _, decl := range f.Decls {
    45  				if decl, ok := decl.(*ast.FuncDecl); ok {
    46  					if decl.Name.Name == funcname {
    47  						g := cfg.New(decl.Body, mayReturn)
    48  						fmt.Println(g.Dot(pkg.Fset))
    49  						os.Exit(0)
    50  					}
    51  				}
    52  			}
    53  		}
    54  	}
    55  	log.Fatalf("no function %q found in %s", funcname, pattern)
    56  }
    57  
    58  // A trivial mayReturn predicate that looks only at syntax, not types.
    59  func mayReturn(call *ast.CallExpr) bool {
    60  	switch fun := call.Fun.(type) {
    61  	case *ast.Ident:
    62  		return fun.Name != "panic"
    63  	case *ast.SelectorExpr:
    64  		return fun.Sel.Name != "Fatal"
    65  	}
    66  	return true
    67  }