.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / cmd / eg / eg.go
1 // Copyright 2014 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 eg command performs example-based refactoring.
6 // For documentation, run the command, or see Help in
7 // golang.org/x/tools/refactor/eg.
8 package main // import "golang.org/x/tools/cmd/eg"
9
10 import (
11         "flag"
12         "fmt"
13         "go/ast"
14         "go/format"
15         "go/parser"
16         "go/token"
17         "go/types"
18         "io/ioutil"
19         "os"
20         "path/filepath"
21         "strings"
22
23         exec "golang.org/x/sys/execabs"
24         "golang.org/x/tools/go/packages"
25         "golang.org/x/tools/refactor/eg"
26 )
27
28 var (
29         beforeeditFlag = flag.String("beforeedit", "", "A command to exec before each file is edited (e.g. chmod, checkout).  Whitespace delimits argument words.  The string '{}' is replaced by the file name.")
30         helpFlag       = flag.Bool("help", false, "show detailed help message")
31         templateFlag   = flag.String("t", "", "template.go file specifying the refactoring")
32         transitiveFlag = flag.Bool("transitive", false, "apply refactoring to all dependencies too")
33         writeFlag      = flag.Bool("w", false, "rewrite input files in place (by default, the results are printed to standard output)")
34         verboseFlag    = flag.Bool("v", false, "show verbose matcher diagnostics")
35 )
36
37 const usage = `eg: an example-based refactoring tool.
38
39 Usage: eg -t template.go [-w] [-transitive] <packages>
40
41 -help            show detailed help message
42 -t template.go   specifies the template file (use -help to see explanation)
43 -w               causes files to be re-written in place.
44 -transitive      causes all dependencies to be refactored too.
45 -v               show verbose matcher diagnostics
46 -beforeedit cmd  a command to exec before each file is modified.
47                  "{}" represents the name of the file.
48 `
49
50 func main() {
51         if err := doMain(); err != nil {
52                 fmt.Fprintf(os.Stderr, "eg: %s\n", err)
53                 os.Exit(1)
54         }
55 }
56
57 func doMain() error {
58         flag.Parse()
59         args := flag.Args()
60
61         if *helpFlag {
62                 fmt.Fprint(os.Stderr, eg.Help)
63                 os.Exit(2)
64         }
65
66         if len(args) == 0 {
67                 fmt.Fprint(os.Stderr, usage)
68                 os.Exit(1)
69         }
70
71         if *templateFlag == "" {
72                 return fmt.Errorf("no -t template.go file specified")
73         }
74
75         tAbs, err := filepath.Abs(*templateFlag)
76         if err != nil {
77                 return err
78         }
79         template, err := ioutil.ReadFile(tAbs)
80         if err != nil {
81                 return err
82         }
83
84         cfg := &packages.Config{
85                 Fset:  token.NewFileSet(),
86                 Mode:  packages.NeedTypesInfo | packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedImports | packages.NeedDeps | packages.NeedCompiledGoFiles,
87                 Tests: true,
88         }
89
90         pkgs, err := packages.Load(cfg, args...)
91         if err != nil {
92                 return err
93         }
94
95         tFile, err := parser.ParseFile(cfg.Fset, tAbs, template, parser.ParseComments)
96         if err != nil {
97                 return err
98         }
99
100         // Type-check the template.
101         tInfo := types.Info{
102                 Types:      make(map[ast.Expr]types.TypeAndValue),
103                 Defs:       make(map[*ast.Ident]types.Object),
104                 Uses:       make(map[*ast.Ident]types.Object),
105                 Implicits:  make(map[ast.Node]types.Object),
106                 Selections: make(map[*ast.SelectorExpr]*types.Selection),
107                 Scopes:     make(map[ast.Node]*types.Scope),
108         }
109         conf := types.Config{
110                 Importer: pkgsImporter(pkgs),
111         }
112         tPkg, err := conf.Check("egtemplate", cfg.Fset, []*ast.File{tFile}, &tInfo)
113         if err != nil {
114                 return err
115         }
116
117         // Analyze the template.
118         xform, err := eg.NewTransformer(cfg.Fset, tPkg, tFile, &tInfo, *verboseFlag)
119         if err != nil {
120                 return err
121         }
122
123         // Apply it to the input packages.
124         var all []*packages.Package
125         if *transitiveFlag {
126                 packages.Visit(pkgs, nil, func(p *packages.Package) { all = append(all, p) })
127         } else {
128                 all = pkgs
129         }
130         var hadErrors bool
131         for _, pkg := range pkgs {
132                 for i, filename := range pkg.CompiledGoFiles {
133                         if filename == tAbs {
134                                 // Don't rewrite the template file.
135                                 continue
136                         }
137                         file := pkg.Syntax[i]
138                         n := xform.Transform(pkg.TypesInfo, pkg.Types, file)
139                         if n == 0 {
140                                 continue
141                         }
142                         fmt.Fprintf(os.Stderr, "=== %s (%d matches)\n", filename, n)
143                         if *writeFlag {
144                                 // Run the before-edit command (e.g. "chmod +w",  "checkout") if any.
145                                 if *beforeeditFlag != "" {
146                                         args := strings.Fields(*beforeeditFlag)
147                                         // Replace "{}" with the filename, like find(1).
148                                         for i := range args {
149                                                 if i > 0 {
150                                                         args[i] = strings.Replace(args[i], "{}", filename, -1)
151                                                 }
152                                         }
153                                         cmd := exec.Command(args[0], args[1:]...)
154                                         cmd.Stdout = os.Stdout
155                                         cmd.Stderr = os.Stderr
156                                         if err := cmd.Run(); err != nil {
157                                                 fmt.Fprintf(os.Stderr, "Warning: edit hook %q failed (%s)\n",
158                                                         args, err)
159                                         }
160                                 }
161                                 if err := eg.WriteAST(cfg.Fset, filename, file); err != nil {
162                                         fmt.Fprintf(os.Stderr, "eg: %s\n", err)
163                                         hadErrors = true
164                                 }
165                         } else {
166                                 format.Node(os.Stdout, cfg.Fset, file)
167                         }
168                 }
169         }
170         if hadErrors {
171                 os.Exit(1)
172         }
173
174         return nil
175 }
176
177 type pkgsImporter []*packages.Package
178
179 func (p pkgsImporter) Import(path string) (tpkg *types.Package, err error) {
180         packages.Visit([]*packages.Package(p), func(pkg *packages.Package) bool {
181                 if pkg.PkgPath == path {
182                         tpkg = pkg.Types
183                         return false
184                 }
185                 return true
186         }, nil)
187         if tpkg != nil {
188                 return tpkg, nil
189         }
190         return nil, fmt.Errorf("package %q not found", path)
191 }