GoPLS Viewer

Home|gopls/cmd/guru/main.go
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// guru: a tool for answering questions about Go source code.
6//
7//    http://golang.org/s/using-guru
8//
9// Run with -help flag or help subcommand for usage information.
10package main // import "golang.org/x/tools/cmd/guru"
11
12import (
13    "bufio"
14    "flag"
15    "fmt"
16    "go/build"
17    "go/token"
18    "io"
19    "log"
20    "os"
21    "path/filepath"
22    "runtime"
23    "runtime/pprof"
24    "strings"
25    "sync"
26
27    "golang.org/x/tools/go/buildutil"
28)
29
30// flags
31var (
32    modifiedFlag   = flag.Bool("modified"false"read archive of modified files from standard input")
33    scopeFlag      = flag.String("scope""""comma-separated list of `packages` the analysis should be limited to")
34    ptalogFlag     = flag.String("ptalog""""write points-to analysis log to `file`")
35    jsonFlag       = flag.Bool("json"false"emit output in JSON format")
36    reflectFlag    = flag.Bool("reflect"false"analyze reflection soundly (slow)")
37    cpuprofileFlag = flag.String("cpuprofile""""write CPU profile to `file`")
38)
39
40func init() {
41    flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags"buildutil.TagsFlagDoc)
42
43    // gccgo does not provide a GOROOT with standard library sources.
44    // If we have one in the environment, force gc mode.
45    if build.Default.Compiler == "gccgo" {
46        if _err := os.Stat(filepath.Join(runtime.GOROOT(), "src""runtime""runtime.go")); err == nil {
47            build.Default.Compiler = "gc"
48        }
49    }
50}
51
52const useHelp = "Run 'guru -help' for more information.\n"
53
54const helpMessage = `Go source code guru.
55Usage: guru [flags] <mode> <position>
56
57The mode argument determines the query to perform:
58
59    callees          show possible targets of selected function call
60    callers          show possible callers of selected function
61    callstack     show path from callgraph root to selected function
62    definition    show declaration of selected identifier
63    describe      describe selected syntax: definition, methods, etc
64    freevars      show free variables of selection
65    implements    show 'implements' relation for selected type or method
66    peers         show send/receive corresponding to selected channel op
67    pointsto    show variables the selected pointer may point to
68    referrers     show all refs to entity denoted by selected identifier
69    what        show basic information about the selected syntax node
70    whicherrs    show possible values of the selected error variable
71
72The position argument specifies the filename and byte offset (or range)
73of the syntax element to query.  For example:
74
75    foo.go:#123,#128
76    bar.go:#123
77
78The -json flag causes guru to emit output in JSON format;
79    golang.org/x/tools/cmd/guru/serial defines its schema.
80    Otherwise, the output is in an editor-friendly format in which
81    every line has the form "pos: text", where pos is "-" if unknown.
82
83The -modified flag causes guru to read an archive from standard input.
84    Files in this archive will be used in preference to those in
85    the file system.  In this way, a text editor may supply guru
86    with the contents of its unsaved buffers.  Each archive entry
87    consists of the file name, a newline, the decimal file size,
88    another newline, and the contents of the file.
89
90The -scope flag restricts analysis to the specified packages.
91    Its value is a comma-separated list of patterns of these forms:
92        golang.org/x/tools/cmd/guru     # a single package
93        golang.org/x/tools/...          # all packages beneath dir
94        ...                             # the entire workspace.
95    A pattern preceded by '-' is negative, so the scope
96        encoding/...,-encoding/xml
97    matches all encoding packages except encoding/xml.
98
99User manual: http://golang.org/s/using-guru
100
101Example: describe syntax at offset 530 in this file (an import spec):
102
103  $ guru describe src/golang.org/x/tools/cmd/guru/main.go:#530
104`
105
106func printHelp() {
107    fmt.Fprint(os.StderrhelpMessage)
108    fmt.Fprintln(os.Stderr"\nFlags:")
109    flag.PrintDefaults()
110}
111
112func main() {
113    log.SetPrefix("guru: ")
114    log.SetFlags(0)
115
116    // Don't print full help unless -help was requested.
117    // Just gently remind users that it's there.
118    flag.Usage = func() { fmt.Fprint(os.StderruseHelp) }
119    flag.CommandLine.Init(os.Args[0], flag.ContinueOnError// hack
120    if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
121        // (err has already been printed)
122        if err == flag.ErrHelp {
123            printHelp()
124        }
125        os.Exit(2)
126    }
127
128    args := flag.Args()
129    if len(args) != 2 {
130        flag.Usage()
131        os.Exit(2)
132    }
133    modeposn := args[0], args[1]
134
135    if mode == "help" {
136        printHelp()
137        os.Exit(2)
138    }
139
140    // Set up points-to analysis log file.
141    var ptalog io.Writer
142    if *ptalogFlag != "" {
143        if ferr := os.Create(*ptalogFlag); err != nil {
144            log.Fatalf("Failed to create PTA log file: %s"err)
145        } else {
146            buf := bufio.NewWriter(f)
147            ptalog = buf
148            defer func() {
149                if err := buf.Flush(); err != nil {
150                    log.Printf("flush: %s"err)
151                }
152                if err := f.Close(); err != nil {
153                    log.Printf("close: %s"err)
154                }
155            }()
156        }
157    }
158
159    // Profiling support.
160    if *cpuprofileFlag != "" {
161        ferr := os.Create(*cpuprofileFlag)
162        if err != nil {
163            log.Fatal(err)
164        }
165        pprof.StartCPUProfile(f)
166        defer pprof.StopCPUProfile()
167    }
168
169    ctxt := &build.Default
170
171    // If there were modified files,
172    // read them from the standard input and
173    // overlay them on the build context.
174    if *modifiedFlag {
175        modifiederr := buildutil.ParseOverlayArchive(os.Stdin)
176        if err != nil {
177            log.Fatal(err)
178        }
179
180        // All I/O done by guru needs to consult the modified map.
181        // The ReadFile done by referrers does,
182        // but the loader's cgo preprocessing currently does not.
183
184        if len(modified) > 0 {
185            ctxt = buildutil.OverlayContext(ctxtmodified)
186        }
187    }
188
189    var outputMu sync.Mutex
190    output := func(fset *token.FileSetqr QueryResult) {
191        outputMu.Lock()
192        defer outputMu.Unlock()
193        if *jsonFlag {
194            // JSON output
195            fmt.Printf("%s\n"qr.JSON(fset))
196        } else {
197            // plain output
198            printf := func(pos interface{}, format stringargs ...interface{}) {
199                fprintf(os.Stdoutfsetposformatargs...)
200            }
201            qr.PrintPlain(printf)
202        }
203    }
204
205    // Avoid corner case of split("").
206    var scope []string
207    if *scopeFlag != "" {
208        scope = strings.Split(*scopeFlag",")
209    }
210
211    // Ask the guru.
212    query := Query{
213        Pos:        posn,
214        Build:      ctxt,
215        Scope:      scope,
216        PTALog:     ptalog,
217        Reflection: *reflectFlag,
218        Output:     output,
219    }
220
221    if err := Run(mode, &query); err != nil {
222        log.Fatal(err)
223    }
224}
225
MembersX
init.BlockStmt._
main.err
main.ptalog
main.BlockStmt.f
main.outputMu
pprof
useHelp
helpMessage
main.args
bufio
main
main.BlockStmt.BlockStmt.BlockStmt.err
main.BlockStmt.modified
main.scope
init.BlockStmt.err
main.BlockStmt.err
main.BlockStmt.BlockStmt.buf
main.query
printHelp
Members
X