Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / 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.
9 package main
10
11 import (
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
26 func main() {
27         tool.Main(context.Background(), &application{Mode: "imports"}, os.Args[1:])
28 }
29
30 type 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.
43 func (app *application) Name() string { return "gopackages" }
44
45 // Usage implements tool.Application returning empty extra argument usage.
46 func (app *application) Usage() string { return "package..." }
47
48 // ShortHelp implements tool.Application returning the main binary help.
49 func (app *application) ShortHelp() 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.
54 func (app *application) DetailedHelp(f *flag.FlagSet) {
55         fmt.Fprint(f.Output(), `
56 Packages are specified using the notation of "go list",
57 or other underlying build system.
58
59 Flags:
60 `)
61         f.PrintDefaults()
62 }
63
64 // Run takes the args after flag processing and performs the specified query.
65 func (app *application) Run(ctx context.Context, args ...string) error {
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                 BuildFlags: app.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         lpkgs, err := packages.Load(cfg, args...)
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(importPaths, path)
113                                 }
114                                 sort.Strings(importPaths) // for determinism
115                                 for _, path := range importPaths {
116                                         visit(lpkg.Imports[path])
117                                 }
118
119                                 all = append(all, lpkg)
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
134 func (app *application) print(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", kind, lpkg.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 importPath, imp := 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", importPath, imp.ID)
179                 }
180                 lines = append(lines, line)
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(obj, qual))
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(meth, qual))
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"}.
219 type stringListValue []string
220
221 func newStringListValue(val []string, p *[]string) *stringListValue {
222         *p = val
223         return (*stringListValue)(p)
224 }
225
226 func (ss *stringListValue) Get() interface{} { return []string(*ss) }
227
228 func (ss *stringListValue) String() string { return fmt.Sprintf("%q", *ss) }
229
230 func (ss *stringListValue) Set(s string) error { *ss = append(*ss, s); return nil }