GoPLS Viewer

Home|gopls/go/packages/gopackages/main.go
1// Copyright 2018 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// The gopackages command is a diagnostic tool that demonstrates
6// how to use golang.org/x/tools/go/packages to load, parse,
7// type-check, and print one or more Go packages.
8// Its precise output is unspecified and may change.
9package main
10
11import (
12    "context"
13    "encoding/json"
14    "flag"
15    "fmt"
16    "go/types"
17    "os"
18    "sort"
19    "strings"
20
21    "golang.org/x/tools/go/packages"
22    "golang.org/x/tools/go/types/typeutil"
23    "golang.org/x/tools/internal/tool"
24)
25
26func main() {
27    tool.Main(context.Background(), &application{Mode"imports"}, os.Args[1:])
28}
29
30type application struct {
31    // Embed the basic profiling flags supported by the tool package
32    tool.Profile
33
34    Deps       bool            `flag:"deps" help:"show dependencies too"`
35    Test       bool            `flag:"test" help:"include any tests implied by the patterns"`
36    Mode       string          `flag:"mode" help:"mode (one of files, imports, types, syntax, allsyntax)"`
37    Private    bool            `flag:"private" help:"show non-exported declarations too"`
38    PrintJSON  bool            `flag:"json" help:"print package in JSON form"`
39    BuildFlags stringListValue `flag:"buildflag" help:"pass argument to underlying build system (may be repeated)"`
40}
41
42// Name implements tool.Application returning the binary name.
43func (app *applicationName() string { return "gopackages" }
44
45// Usage implements tool.Application returning empty extra argument usage.
46func (app *applicationUsage() string { return "package..." }
47
48// ShortHelp implements tool.Application returning the main binary help.
49func (app *applicationShortHelp() string {
50    return "gopackages loads, parses, type-checks, and prints one or more Go packages."
51}
52
53// DetailedHelp implements tool.Application returning the main binary help.
54func (app *applicationDetailedHelp(f *flag.FlagSet) {
55    fmt.Fprint(f.Output(), `
56Packages are specified using the notation of "go list",
57or other underlying build system.
58
59Flags:
60`)
61    f.PrintDefaults()
62}
63
64// Run takes the args after flag processing and performs the specified query.
65func (app *applicationRun(ctx context.Contextargs ...stringerror {
66    if len(args) == 0 {
67        return tool.CommandLineErrorf("not enough arguments")
68    }
69
70    // Load, parse, and type-check the packages named on the command line.
71    cfg := &packages.Config{
72        Mode:       packages.LoadSyntax,
73        Tests:      app.Test,
74        BuildFlagsapp.BuildFlags,
75    }
76
77    // -mode flag
78    switch strings.ToLower(app.Mode) {
79    case "files":
80        cfg.Mode = packages.LoadFiles
81    case "imports":
82        cfg.Mode = packages.LoadImports
83    case "types":
84        cfg.Mode = packages.LoadTypes
85    case "syntax":
86        cfg.Mode = packages.LoadSyntax
87    case "allsyntax":
88        cfg.Mode = packages.LoadAllSyntax
89    default:
90        return tool.CommandLineErrorf("invalid mode: %s"app.Mode)
91    }
92
93    lpkgserr := packages.Load(cfgargs...)
94    if err != nil {
95        return err
96    }
97
98    // -deps: print dependencies too.
99    if app.Deps {
100        // We can't use packages.All because
101        // we need an ordered traversal.
102        var all []*packages.Package // postorder
103        seen := make(map[*packages.Package]bool)
104        var visit func(*packages.Package)
105        visit = func(lpkg *packages.Package) {
106            if !seen[lpkg] {
107                seen[lpkg] = true
108
109                // visit imports
110                var importPaths []string
111                for path := range lpkg.Imports {
112                    importPaths = append(importPathspath)
113                }
114                sort.Strings(importPaths// for determinism
115                for _path := range importPaths {
116                    visit(lpkg.Imports[path])
117                }
118
119                all = append(alllpkg)
120            }
121        }
122        for _lpkg := range lpkgs {
123            visit(lpkg)
124        }
125        lpkgs = all
126    }
127
128    for _lpkg := range lpkgs {
129        app.print(lpkg)
130    }
131    return nil
132}
133
134func (app *applicationprint(lpkg *packages.Package) {
135    if app.PrintJSON {
136        data_ := json.MarshalIndent(lpkg"""\t")
137        os.Stdout.Write(data)
138        return
139    }
140    // title
141    var kind string
142    // TODO(matloob): If IsTest is added back print "test command" or
143    // "test package" for packages with IsTest == true.
144    if lpkg.Name == "main" {
145        kind += "command"
146    } else {
147        kind += "package"
148    }
149    fmt.Printf("Go %s %q:\n"kindlpkg.ID// unique ID
150    fmt.Printf("\tpackage %s\n"lpkg.Name)
151
152    // characterize type info
153    if lpkg.Types == nil {
154        fmt.Printf("\thas no exported type info\n")
155    } else if !lpkg.Types.Complete() {
156        fmt.Printf("\thas incomplete exported type info\n")
157    } else if len(lpkg.Syntax) == 0 {
158        fmt.Printf("\thas complete exported type info\n")
159    } else {
160        fmt.Printf("\thas complete exported type info and typed ASTs\n")
161    }
162    if lpkg.Types != nil && lpkg.IllTyped && len(lpkg.Errors) == 0 {
163        fmt.Printf("\thas an error among its dependencies\n")
164    }
165
166    // source files
167    for _src := range lpkg.GoFiles {
168        fmt.Printf("\tfile %s\n"src)
169    }
170
171    // imports
172    var lines []string
173    for importPathimp := range lpkg.Imports {
174        var line string
175        if imp.ID == importPath {
176            line = fmt.Sprintf("\timport %q"importPath)
177        } else {
178            line = fmt.Sprintf("\timport %q => %q"importPathimp.ID)
179        }
180        lines = append(linesline)
181    }
182    sort.Strings(lines)
183    for _line := range lines {
184        fmt.Println(line)
185    }
186
187    // errors
188    for _err := range lpkg.Errors {
189        fmt.Printf("\t%s\n"err)
190    }
191
192    // package members (TypeCheck or WholeProgram mode)
193    if lpkg.Types != nil {
194        qual := types.RelativeTo(lpkg.Types)
195        scope := lpkg.Types.Scope()
196        for _name := range scope.Names() {
197            obj := scope.Lookup(name)
198            if !obj.Exported() && !app.Private {
199                continue // skip unexported names
200            }
201
202            fmt.Printf("\t%s\n"types.ObjectString(objqual))
203            if _ok := obj.(*types.TypeName); ok {
204                for _meth := range typeutil.IntuitiveMethodSet(obj.Type(), nil) {
205                    if !meth.Obj().Exported() && !app.Private {
206                        continue // skip unexported names
207                    }
208                    fmt.Printf("\t%s\n"types.SelectionString(methqual))
209                }
210            }
211        }
212    }
213
214    fmt.Println()
215}
216
217// stringListValue is a flag.Value that accumulates strings.
218// e.g. --flag=one --flag=two would produce []string{"one", "two"}.
219type stringListValue []string
220
221func newStringListValue(val []stringp *[]string) *stringListValue {
222    *p = val
223    return (*stringListValue)(p)
224}
225
226func (ss *stringListValueGet() interface{} { return []string(*ss) }
227
228func (ss *stringListValueString() string { return fmt.Sprintf("%q", *ss) }
229
230func (ss *stringListValueSet(s stringerror { *ss = append(*sss); return nil }
231
MembersX
application
application.Mode
application.print.RangeStmt_4832.imp
stringListValue.String.ss
application.DetailedHelp
application.Run.BlockStmt.BlockStmt.BlockStmt.importPaths
application.print.app
newStringListValue.p
application.print.lpkg
application.print.RangeStmt_5104.line
application.print.BlockStmt.RangeStmt_5383.BlockStmt.obj
stringListValue.Get
application.print.kind
json
application.DetailedHelp.f
application.Run.args
application.Run.BlockStmt.seen
application.Run.BlockStmt.BlockStmt.BlockStmt.RangeStmt_3365.path
fmt
sort
application.Deps
application.Run.ctx
application.print.RangeStmt_4832.importPath
application.print.BlockStmt._
newStringListValue.val
os
tool
application.Usage.app
application.Usage
stringListValue.Set.s
application.Private
application.DetailedHelp.app
application.print.BlockStmt.RangeStmt_5383.BlockStmt.BlockStmt.RangeStmt_5635.meth
newStringListValue
application.Run.err
application.print
application.print.lines
application.print.RangeStmt_4832.BlockStmt.line
context
typeutil
application.Name
application.Run.app
application.Run.cfg
application.print.BlockStmt.data
flag
packages
application.Test
application.ShortHelp
application.print.RangeStmt_4727.src
application.print.RangeStmt_5169.err
stringListValue
stringListValue.String
strings
application.Name.app
application.Run.BlockStmt.BlockStmt.BlockStmt.RangeStmt_3502.path
application.Run.BlockStmt.RangeStmt_3614.lpkg
application.PrintJSON
application.Run.lpkgs
application.Run.BlockStmt.all
application.print.BlockStmt.qual
application.Run
application.Run.RangeStmt_3681.lpkg
application.print.BlockStmt.RangeStmt_5383.name
stringListValue.Get.ss
application.BuildFlags
application.ShortHelp.app
stringListValue.Set
types
main
application.print.BlockStmt.scope
stringListValue.Set.ss
Members
X