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 }