github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/cmd/oracle/main.go (about)

     1  // Copyright 2013 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  // oracle: a tool for answering questions about Go source code.
     6  // http://golang.org/s/oracle-design
     7  // http://golang.org/s/oracle-user-manual
     8  //
     9  // Run with -help flag or help subcommand for usage information.
    10  //
    11  package main // import "golang.org/x/tools/cmd/oracle"
    12  
    13  import (
    14  	"bufio"
    15  	"encoding/json"
    16  	"encoding/xml"
    17  	"flag"
    18  	"fmt"
    19  	"go/build"
    20  	"io"
    21  	"log"
    22  	"os"
    23  	"runtime"
    24  	"runtime/pprof"
    25  
    26  	"golang.org/x/tools/go/buildutil"
    27  	"golang.org/x/tools/go/loader"
    28  	"golang.org/x/tools/oracle"
    29  )
    30  
    31  var posFlag = flag.String("pos", "",
    32  	"Filename and byte offset or extent of a syntax element about which to query, "+
    33  		"e.g. foo.go:#123,#456, bar.go:#123.")
    34  
    35  var ptalogFlag = flag.String("ptalog", "",
    36  	"Location of the points-to analysis log file, or empty to disable logging.")
    37  
    38  var formatFlag = flag.String("format", "plain", "Output format.  One of {plain,json,xml}.")
    39  
    40  var reflectFlag = flag.Bool("reflect", false, "Analyze reflection soundly (slow).")
    41  
    42  func init() {
    43  	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
    44  }
    45  
    46  const useHelp = "Run 'oracle -help' for more information.\n"
    47  
    48  const helpMessage = `Go source code oracle.
    49  Usage: oracle [<flag> ...] <mode> <args> ...
    50  
    51  The -format flag controls the output format:
    52  	plain	an editor-friendly format in which every line of output
    53  		is of the form "pos: text", where pos is "-" if unknown.
    54  	json	structured data in JSON syntax.
    55  	xml	structured data in XML syntax.
    56  
    57  The -pos flag is required in all modes.
    58  
    59  The mode argument determines the query to perform:
    60  
    61  	callees	  	show possible targets of selected function call
    62  	callers	  	show possible callers of selected function
    63  	callstack 	show path from callgraph root to selected function
    64  	definition	show declaration of selected identifier
    65  	describe  	describe selected syntax: definition, methods, etc
    66  	freevars  	show free variables of selection
    67  	implements	show 'implements' relation for selected type or method
    68  	peers     	show send/receive corresponding to selected channel op
    69  	referrers 	show all refs to entity denoted by selected identifier
    70  	what		show basic information about the selected syntax node
    71  
    72  The user manual is available here:  http://golang.org/s/oracle-user-manual
    73  
    74  Examples:
    75  
    76  Describe the syntax at offset 530 in this file (an import spec):
    77  % oracle -pos=src/golang.org/x/tools/cmd/oracle/main.go:#530 describe \
    78     golang.org/x/tools/cmd/oracle
    79  
    80  Print the callgraph of the trivial web-server in JSON format:
    81  % oracle -format=json callstack $GOROOT/src/net/http/triv.go
    82  ` + loader.FromArgsUsage
    83  
    84  var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
    85  
    86  func init() {
    87  	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
    88  	// For small machines, use at least 4 threads.
    89  	if os.Getenv("GOMAXPROCS") == "" {
    90  		n := runtime.NumCPU()
    91  		if n < 4 {
    92  			n = 4
    93  		}
    94  		runtime.GOMAXPROCS(n)
    95  	}
    96  }
    97  
    98  func printHelp() {
    99  	fmt.Fprintln(os.Stderr, helpMessage)
   100  	fmt.Fprintln(os.Stderr, "Flags:")
   101  	flag.PrintDefaults()
   102  }
   103  
   104  func main() {
   105  	// Don't print full help unless -help was requested.
   106  	// Just gently remind users that it's there.
   107  	flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) }
   108  	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError) // hack
   109  	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
   110  		// (err has already been printed)
   111  		if err == flag.ErrHelp {
   112  			printHelp()
   113  		}
   114  		os.Exit(2)
   115  	}
   116  
   117  	args := flag.Args()
   118  	if len(args) == 0 || args[0] == "" {
   119  		fmt.Fprint(os.Stderr, "oracle: a mode argument is required.\n"+useHelp)
   120  		os.Exit(2)
   121  	}
   122  
   123  	mode := args[0]
   124  	args = args[1:]
   125  	if mode == "help" {
   126  		printHelp()
   127  		os.Exit(2)
   128  	}
   129  
   130  	// Set up points-to analysis log file.
   131  	var ptalog io.Writer
   132  	if *ptalogFlag != "" {
   133  		if f, err := os.Create(*ptalogFlag); err != nil {
   134  			log.Fatalf("Failed to create PTA log file: %s", err)
   135  		} else {
   136  			buf := bufio.NewWriter(f)
   137  			ptalog = buf
   138  			defer func() {
   139  				if err := buf.Flush(); err != nil {
   140  					log.Printf("flush: %s", err)
   141  				}
   142  				if err := f.Close(); err != nil {
   143  					log.Printf("close: %s", err)
   144  				}
   145  			}()
   146  		}
   147  	}
   148  
   149  	// Profiling support.
   150  	if *cpuprofile != "" {
   151  		f, err := os.Create(*cpuprofile)
   152  		if err != nil {
   153  			log.Fatal(err)
   154  		}
   155  		pprof.StartCPUProfile(f)
   156  		defer pprof.StopCPUProfile()
   157  	}
   158  
   159  	// -format flag
   160  	switch *formatFlag {
   161  	case "json", "plain", "xml":
   162  		// ok
   163  	default:
   164  		fmt.Fprintf(os.Stderr, "oracle: illegal -format value: %q.\n"+useHelp, *formatFlag)
   165  		os.Exit(2)
   166  	}
   167  
   168  	// Ask the oracle.
   169  	query := oracle.Query{
   170  		Mode:       mode,
   171  		Pos:        *posFlag,
   172  		Build:      &build.Default,
   173  		Scope:      args,
   174  		PTALog:     ptalog,
   175  		Reflection: *reflectFlag,
   176  	}
   177  
   178  	if err := oracle.Run(&query); err != nil {
   179  		fmt.Fprintf(os.Stderr, "oracle: %s\n", err)
   180  		os.Exit(1)
   181  	}
   182  
   183  	// Print the result.
   184  	switch *formatFlag {
   185  	case "json":
   186  		b, err := json.MarshalIndent(query.Serial(), "", "\t")
   187  		if err != nil {
   188  			fmt.Fprintf(os.Stderr, "oracle: JSON error: %s\n", err)
   189  			os.Exit(1)
   190  		}
   191  		os.Stdout.Write(b)
   192  
   193  	case "xml":
   194  		b, err := xml.MarshalIndent(query.Serial(), "", "\t")
   195  		if err != nil {
   196  			fmt.Fprintf(os.Stderr, "oracle: XML error: %s\n", err)
   197  			os.Exit(1)
   198  		}
   199  		os.Stdout.Write(b)
   200  
   201  	case "plain":
   202  		query.WriteTo(os.Stdout)
   203  	}
   204  }