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 / refactor / 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 // Package eg implements the example-based refactoring tool whose
6 // command-line is defined in golang.org/x/tools/cmd/eg.
7 package eg // import "golang.org/x/tools/refactor/eg"
8
9 import (
10         "bytes"
11         "fmt"
12         "go/ast"
13         "go/format"
14         "go/printer"
15         "go/token"
16         "go/types"
17         "os"
18 )
19
20 const Help = `
21 This tool implements example-based refactoring of expressions.
22
23 The transformation is specified as a Go file defining two functions,
24 'before' and 'after', of identical types.  Each function body consists
25 of a single statement: either a return statement with a single
26 (possibly multi-valued) expression, or an expression statement.  The
27 'before' expression specifies a pattern and the 'after' expression its
28 replacement.
29
30         package P
31         import ( "errors"; "fmt" )
32         func before(s string) error { return fmt.Errorf("%s", s) }
33         func after(s string)  error { return errors.New(s) }
34
35 The expression statement form is useful when the expression has no
36 result, for example:
37
38         func before(msg string) { log.Fatalf("%s", msg) }
39         func after(msg string)  { log.Fatal(msg) }
40
41 The parameters of both functions are wildcards that may match any
42 expression assignable to that type.  If the pattern contains multiple
43 occurrences of the same parameter, each must match the same expression
44 in the input for the pattern to match.  If the replacement contains
45 multiple occurrences of the same parameter, the expression will be
46 duplicated, possibly changing the side-effects.
47
48 The tool analyses all Go code in the packages specified by the
49 arguments, replacing all occurrences of the pattern with the
50 substitution.
51
52 So, the transform above would change this input:
53         err := fmt.Errorf("%s", "error: " + msg)
54 to this output:
55         err := errors.New("error: " + msg)
56
57 Identifiers, including qualified identifiers (p.X) are considered to
58 match only if they denote the same object.  This allows correct
59 matching even in the presence of dot imports, named imports and
60 locally shadowed package names in the input program.
61
62 Matching of type syntax is semantic, not syntactic: type syntax in the
63 pattern matches type syntax in the input if the types are identical.
64 Thus, func(x int) matches func(y int).
65
66 This tool was inspired by other example-based refactoring tools,
67 'gofmt -r' for Go and Refaster for Java.
68
69
70 LIMITATIONS
71 ===========
72
73 EXPRESSIVENESS
74
75 Only refactorings that replace one expression with another, regardless
76 of the expression's context, may be expressed.  Refactoring arbitrary
77 statements (or sequences of statements) is a less well-defined problem
78 and is less amenable to this approach.
79
80 A pattern that contains a function literal (and hence statements)
81 never matches.
82
83 There is no way to generalize over related types, e.g. to express that
84 a wildcard may have any integer type, for example.
85
86 It is not possible to replace an expression by one of a different
87 type, even in contexts where this is legal, such as x in fmt.Print(x).
88
89 The struct literals T{x} and T{K: x} cannot both be matched by a single
90 template.
91
92
93 SAFETY
94
95 Verifying that a transformation does not introduce type errors is very
96 complex in the general case.  An innocuous-looking replacement of one
97 constant by another (e.g. 1 to 2) may cause type errors relating to
98 array types and indices, for example.  The tool performs only very
99 superficial checks of type preservation.
100
101
102 IMPORTS
103
104 Although the matching algorithm is fully aware of scoping rules, the
105 replacement algorithm is not, so the replacement code may contain
106 incorrect identifier syntax for imported objects if there are dot
107 imports, named imports or locally shadowed package names in the input
108 program.
109
110 Imports are added as needed, but they are not removed as needed.
111 Run 'goimports' on the modified file for now.
112
113 Dot imports are forbidden in the template.
114
115
116 TIPS
117 ====
118
119 Sometimes a little creativity is required to implement the desired
120 migration.  This section lists a few tips and tricks.
121
122 To remove the final parameter from a function, temporarily change the
123 function signature so that the final parameter is variadic, as this
124 allows legal calls both with and without the argument.  Then use eg to
125 remove the final argument from all callers, and remove the variadic
126 parameter by hand.  The reverse process can be used to add a final
127 parameter.
128
129 To add or remove parameters other than the final one, you must do it in
130 stages: (1) declare a variant function f' with a different name and the
131 desired parameters; (2) use eg to transform calls to f into calls to f',
132 changing the arguments as needed; (3) change the declaration of f to
133 match f'; (4) use eg to rename f' to f in all calls; (5) delete f'.
134 `
135
136 // TODO(adonovan): expand upon the above documentation as an HTML page.
137
138 // A Transformer represents a single example-based transformation.
139 type Transformer struct {
140         fset           *token.FileSet
141         verbose        bool
142         info           *types.Info // combined type info for template/input/output ASTs
143         seenInfos      map[*types.Info]bool
144         wildcards      map[*types.Var]bool                // set of parameters in func before()
145         env            map[string]ast.Expr                // maps parameter name to wildcard binding
146         importedObjs   map[types.Object]*ast.SelectorExpr // objects imported by after().
147         before, after  ast.Expr
148         afterStmts     []ast.Stmt
149         allowWildcards bool
150
151         // Working state of Transform():
152         nsubsts    int            // number of substitutions made
153         currentPkg *types.Package // package of current call
154 }
155
156 // NewTransformer returns a transformer based on the specified template,
157 // a single-file package containing "before" and "after" functions as
158 // described in the package documentation.
159 // tmplInfo is the type information for tmplFile.
160 //
161 func NewTransformer(fset *token.FileSet, tmplPkg *types.Package, tmplFile *ast.File, tmplInfo *types.Info, verbose bool) (*Transformer, error) {
162         // Check the template.
163         beforeSig := funcSig(tmplPkg, "before")
164         if beforeSig == nil {
165                 return nil, fmt.Errorf("no 'before' func found in template")
166         }
167         afterSig := funcSig(tmplPkg, "after")
168         if afterSig == nil {
169                 return nil, fmt.Errorf("no 'after' func found in template")
170         }
171
172         // TODO(adonovan): should we also check the names of the params match?
173         if !types.Identical(afterSig, beforeSig) {
174                 return nil, fmt.Errorf("before %s and after %s functions have different signatures",
175                         beforeSig, afterSig)
176         }
177
178         for _, imp := range tmplFile.Imports {
179                 if imp.Name != nil && imp.Name.Name == "." {
180                         // Dot imports are currently forbidden.  We
181                         // make the simplifying assumption that all
182                         // imports are regular, without local renames.
183                         return nil, fmt.Errorf("dot-import (of %s) in template", imp.Path.Value)
184                 }
185         }
186         var beforeDecl, afterDecl *ast.FuncDecl
187         for _, decl := range tmplFile.Decls {
188                 if decl, ok := decl.(*ast.FuncDecl); ok {
189                         switch decl.Name.Name {
190                         case "before":
191                                 beforeDecl = decl
192                         case "after":
193                                 afterDecl = decl
194                         }
195                 }
196         }
197
198         before, err := soleExpr(beforeDecl)
199         if err != nil {
200                 return nil, fmt.Errorf("before: %s", err)
201         }
202         afterStmts, after, err := stmtAndExpr(afterDecl)
203         if err != nil {
204                 return nil, fmt.Errorf("after: %s", err)
205         }
206
207         wildcards := make(map[*types.Var]bool)
208         for i := 0; i < beforeSig.Params().Len(); i++ {
209                 wildcards[beforeSig.Params().At(i)] = true
210         }
211
212         // checkExprTypes returns an error if Tb (type of before()) is not
213         // safe to replace with Ta (type of after()).
214         //
215         // Only superficial checks are performed, and they may result in both
216         // false positives and negatives.
217         //
218         // Ideally, we would only require that the replacement be assignable
219         // to the context of a specific pattern occurrence, but the type
220         // checker doesn't record that information and it's complex to deduce.
221         // A Go type cannot capture all the constraints of a given expression
222         // context, which may include the size, constness, signedness,
223         // namedness or constructor of its type, and even the specific value
224         // of the replacement.  (Consider the rule that array literal keys
225         // must be unique.)  So we cannot hope to prove the safety of a
226         // transformation in general.
227         Tb := tmplInfo.TypeOf(before)
228         Ta := tmplInfo.TypeOf(after)
229         if types.AssignableTo(Tb, Ta) {
230                 // safe: replacement is assignable to pattern.
231         } else if tuple, ok := Tb.(*types.Tuple); ok && tuple.Len() == 0 {
232                 // safe: pattern has void type (must appear in an ExprStmt).
233         } else {
234                 return nil, fmt.Errorf("%s is not a safe replacement for %s", Ta, Tb)
235         }
236
237         tr := &Transformer{
238                 fset:           fset,
239                 verbose:        verbose,
240                 wildcards:      wildcards,
241                 allowWildcards: true,
242                 seenInfos:      make(map[*types.Info]bool),
243                 importedObjs:   make(map[types.Object]*ast.SelectorExpr),
244                 before:         before,
245                 after:          after,
246                 afterStmts:     afterStmts,
247         }
248
249         // Combine type info from the template and input packages, and
250         // type info for the synthesized ASTs too.  This saves us
251         // having to book-keep where each ast.Node originated as we
252         // construct the resulting hybrid AST.
253         tr.info = &types.Info{
254                 Types:      make(map[ast.Expr]types.TypeAndValue),
255                 Defs:       make(map[*ast.Ident]types.Object),
256                 Uses:       make(map[*ast.Ident]types.Object),
257                 Selections: make(map[*ast.SelectorExpr]*types.Selection),
258         }
259         mergeTypeInfo(tr.info, tmplInfo)
260
261         // Compute set of imported objects required by after().
262         // TODO(adonovan): reject dot-imports in pattern
263         ast.Inspect(after, func(n ast.Node) bool {
264                 if n, ok := n.(*ast.SelectorExpr); ok {
265                         if _, ok := tr.info.Selections[n]; !ok {
266                                 // qualified ident
267                                 obj := tr.info.Uses[n.Sel]
268                                 tr.importedObjs[obj] = n
269                                 return false // prune
270                         }
271                 }
272                 return true // recur
273         })
274
275         return tr, nil
276 }
277
278 // WriteAST is a convenience function that writes AST f to the specified file.
279 func WriteAST(fset *token.FileSet, filename string, f *ast.File) (err error) {
280         fh, err := os.Create(filename)
281         if err != nil {
282                 return err
283         }
284
285         defer func() {
286                 if err2 := fh.Close(); err != nil {
287                         err = err2 // prefer earlier error
288                 }
289         }()
290         return format.Node(fh, fset, f)
291 }
292
293 // -- utilities --------------------------------------------------------
294
295 // funcSig returns the signature of the specified package-level function.
296 func funcSig(pkg *types.Package, name string) *types.Signature {
297         if f, ok := pkg.Scope().Lookup(name).(*types.Func); ok {
298                 return f.Type().(*types.Signature)
299         }
300         return nil
301 }
302
303 // soleExpr returns the sole expression in the before/after template function.
304 func soleExpr(fn *ast.FuncDecl) (ast.Expr, error) {
305         if fn.Body == nil {
306                 return nil, fmt.Errorf("no body")
307         }
308         if len(fn.Body.List) != 1 {
309                 return nil, fmt.Errorf("must contain a single statement")
310         }
311         switch stmt := fn.Body.List[0].(type) {
312         case *ast.ReturnStmt:
313                 if len(stmt.Results) != 1 {
314                         return nil, fmt.Errorf("return statement must have a single operand")
315                 }
316                 return stmt.Results[0], nil
317
318         case *ast.ExprStmt:
319                 return stmt.X, nil
320         }
321
322         return nil, fmt.Errorf("must contain a single return or expression statement")
323 }
324
325 // stmtAndExpr returns the expression in the last return statement as well as the preceding lines.
326 func stmtAndExpr(fn *ast.FuncDecl) ([]ast.Stmt, ast.Expr, error) {
327         if fn.Body == nil {
328                 return nil, nil, fmt.Errorf("no body")
329         }
330
331         n := len(fn.Body.List)
332         if n == 0 {
333                 return nil, nil, fmt.Errorf("must contain at least one statement")
334         }
335
336         stmts, last := fn.Body.List[:n-1], fn.Body.List[n-1]
337
338         switch last := last.(type) {
339         case *ast.ReturnStmt:
340                 if len(last.Results) != 1 {
341                         return nil, nil, fmt.Errorf("return statement must have a single operand")
342                 }
343                 return stmts, last.Results[0], nil
344
345         case *ast.ExprStmt:
346                 return stmts, last.X, nil
347         }
348
349         return nil, nil, fmt.Errorf("must end with a single return or expression statement")
350 }
351
352 // mergeTypeInfo adds type info from src to dst.
353 func mergeTypeInfo(dst, src *types.Info) {
354         for k, v := range src.Types {
355                 dst.Types[k] = v
356         }
357         for k, v := range src.Defs {
358                 dst.Defs[k] = v
359         }
360         for k, v := range src.Uses {
361                 dst.Uses[k] = v
362         }
363         for k, v := range src.Selections {
364                 dst.Selections[k] = v
365         }
366 }
367
368 // (debugging only)
369 func astString(fset *token.FileSet, n ast.Node) string {
370         var buf bytes.Buffer
371         printer.Fprint(&buf, fset, n)
372         return buf.String()
373 }