.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / refactor / eg / eg.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/refactor/eg/eg.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/refactor/eg/eg.go
new file mode 100644 (file)
index 0000000..0cd1937
--- /dev/null
@@ -0,0 +1,373 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package eg implements the example-based refactoring tool whose
+// command-line is defined in golang.org/x/tools/cmd/eg.
+package eg // import "golang.org/x/tools/refactor/eg"
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/format"
+       "go/printer"
+       "go/token"
+       "go/types"
+       "os"
+)
+
+const Help = `
+This tool implements example-based refactoring of expressions.
+
+The transformation is specified as a Go file defining two functions,
+'before' and 'after', of identical types.  Each function body consists
+of a single statement: either a return statement with a single
+(possibly multi-valued) expression, or an expression statement.  The
+'before' expression specifies a pattern and the 'after' expression its
+replacement.
+
+       package P
+       import ( "errors"; "fmt" )
+       func before(s string) error { return fmt.Errorf("%s", s) }
+       func after(s string)  error { return errors.New(s) }
+
+The expression statement form is useful when the expression has no
+result, for example:
+
+       func before(msg string) { log.Fatalf("%s", msg) }
+       func after(msg string)  { log.Fatal(msg) }
+
+The parameters of both functions are wildcards that may match any
+expression assignable to that type.  If the pattern contains multiple
+occurrences of the same parameter, each must match the same expression
+in the input for the pattern to match.  If the replacement contains
+multiple occurrences of the same parameter, the expression will be
+duplicated, possibly changing the side-effects.
+
+The tool analyses all Go code in the packages specified by the
+arguments, replacing all occurrences of the pattern with the
+substitution.
+
+So, the transform above would change this input:
+       err := fmt.Errorf("%s", "error: " + msg)
+to this output:
+       err := errors.New("error: " + msg)
+
+Identifiers, including qualified identifiers (p.X) are considered to
+match only if they denote the same object.  This allows correct
+matching even in the presence of dot imports, named imports and
+locally shadowed package names in the input program.
+
+Matching of type syntax is semantic, not syntactic: type syntax in the
+pattern matches type syntax in the input if the types are identical.
+Thus, func(x int) matches func(y int).
+
+This tool was inspired by other example-based refactoring tools,
+'gofmt -r' for Go and Refaster for Java.
+
+
+LIMITATIONS
+===========
+
+EXPRESSIVENESS
+
+Only refactorings that replace one expression with another, regardless
+of the expression's context, may be expressed.  Refactoring arbitrary
+statements (or sequences of statements) is a less well-defined problem
+and is less amenable to this approach.
+
+A pattern that contains a function literal (and hence statements)
+never matches.
+
+There is no way to generalize over related types, e.g. to express that
+a wildcard may have any integer type, for example.
+
+It is not possible to replace an expression by one of a different
+type, even in contexts where this is legal, such as x in fmt.Print(x).
+
+The struct literals T{x} and T{K: x} cannot both be matched by a single
+template.
+
+
+SAFETY
+
+Verifying that a transformation does not introduce type errors is very
+complex in the general case.  An innocuous-looking replacement of one
+constant by another (e.g. 1 to 2) may cause type errors relating to
+array types and indices, for example.  The tool performs only very
+superficial checks of type preservation.
+
+
+IMPORTS
+
+Although the matching algorithm is fully aware of scoping rules, the
+replacement algorithm is not, so the replacement code may contain
+incorrect identifier syntax for imported objects if there are dot
+imports, named imports or locally shadowed package names in the input
+program.
+
+Imports are added as needed, but they are not removed as needed.
+Run 'goimports' on the modified file for now.
+
+Dot imports are forbidden in the template.
+
+
+TIPS
+====
+
+Sometimes a little creativity is required to implement the desired
+migration.  This section lists a few tips and tricks.
+
+To remove the final parameter from a function, temporarily change the
+function signature so that the final parameter is variadic, as this
+allows legal calls both with and without the argument.  Then use eg to
+remove the final argument from all callers, and remove the variadic
+parameter by hand.  The reverse process can be used to add a final
+parameter.
+
+To add or remove parameters other than the final one, you must do it in
+stages: (1) declare a variant function f' with a different name and the
+desired parameters; (2) use eg to transform calls to f into calls to f',
+changing the arguments as needed; (3) change the declaration of f to
+match f'; (4) use eg to rename f' to f in all calls; (5) delete f'.
+`
+
+// TODO(adonovan): expand upon the above documentation as an HTML page.
+
+// A Transformer represents a single example-based transformation.
+type Transformer struct {
+       fset           *token.FileSet
+       verbose        bool
+       info           *types.Info // combined type info for template/input/output ASTs
+       seenInfos      map[*types.Info]bool
+       wildcards      map[*types.Var]bool                // set of parameters in func before()
+       env            map[string]ast.Expr                // maps parameter name to wildcard binding
+       importedObjs   map[types.Object]*ast.SelectorExpr // objects imported by after().
+       before, after  ast.Expr
+       afterStmts     []ast.Stmt
+       allowWildcards bool
+
+       // Working state of Transform():
+       nsubsts    int            // number of substitutions made
+       currentPkg *types.Package // package of current call
+}
+
+// NewTransformer returns a transformer based on the specified template,
+// a single-file package containing "before" and "after" functions as
+// described in the package documentation.
+// tmplInfo is the type information for tmplFile.
+//
+func NewTransformer(fset *token.FileSet, tmplPkg *types.Package, tmplFile *ast.File, tmplInfo *types.Info, verbose bool) (*Transformer, error) {
+       // Check the template.
+       beforeSig := funcSig(tmplPkg, "before")
+       if beforeSig == nil {
+               return nil, fmt.Errorf("no 'before' func found in template")
+       }
+       afterSig := funcSig(tmplPkg, "after")
+       if afterSig == nil {
+               return nil, fmt.Errorf("no 'after' func found in template")
+       }
+
+       // TODO(adonovan): should we also check the names of the params match?
+       if !types.Identical(afterSig, beforeSig) {
+               return nil, fmt.Errorf("before %s and after %s functions have different signatures",
+                       beforeSig, afterSig)
+       }
+
+       for _, imp := range tmplFile.Imports {
+               if imp.Name != nil && imp.Name.Name == "." {
+                       // Dot imports are currently forbidden.  We
+                       // make the simplifying assumption that all
+                       // imports are regular, without local renames.
+                       return nil, fmt.Errorf("dot-import (of %s) in template", imp.Path.Value)
+               }
+       }
+       var beforeDecl, afterDecl *ast.FuncDecl
+       for _, decl := range tmplFile.Decls {
+               if decl, ok := decl.(*ast.FuncDecl); ok {
+                       switch decl.Name.Name {
+                       case "before":
+                               beforeDecl = decl
+                       case "after":
+                               afterDecl = decl
+                       }
+               }
+       }
+
+       before, err := soleExpr(beforeDecl)
+       if err != nil {
+               return nil, fmt.Errorf("before: %s", err)
+       }
+       afterStmts, after, err := stmtAndExpr(afterDecl)
+       if err != nil {
+               return nil, fmt.Errorf("after: %s", err)
+       }
+
+       wildcards := make(map[*types.Var]bool)
+       for i := 0; i < beforeSig.Params().Len(); i++ {
+               wildcards[beforeSig.Params().At(i)] = true
+       }
+
+       // checkExprTypes returns an error if Tb (type of before()) is not
+       // safe to replace with Ta (type of after()).
+       //
+       // Only superficial checks are performed, and they may result in both
+       // false positives and negatives.
+       //
+       // Ideally, we would only require that the replacement be assignable
+       // to the context of a specific pattern occurrence, but the type
+       // checker doesn't record that information and it's complex to deduce.
+       // A Go type cannot capture all the constraints of a given expression
+       // context, which may include the size, constness, signedness,
+       // namedness or constructor of its type, and even the specific value
+       // of the replacement.  (Consider the rule that array literal keys
+       // must be unique.)  So we cannot hope to prove the safety of a
+       // transformation in general.
+       Tb := tmplInfo.TypeOf(before)
+       Ta := tmplInfo.TypeOf(after)
+       if types.AssignableTo(Tb, Ta) {
+               // safe: replacement is assignable to pattern.
+       } else if tuple, ok := Tb.(*types.Tuple); ok && tuple.Len() == 0 {
+               // safe: pattern has void type (must appear in an ExprStmt).
+       } else {
+               return nil, fmt.Errorf("%s is not a safe replacement for %s", Ta, Tb)
+       }
+
+       tr := &Transformer{
+               fset:           fset,
+               verbose:        verbose,
+               wildcards:      wildcards,
+               allowWildcards: true,
+               seenInfos:      make(map[*types.Info]bool),
+               importedObjs:   make(map[types.Object]*ast.SelectorExpr),
+               before:         before,
+               after:          after,
+               afterStmts:     afterStmts,
+       }
+
+       // Combine type info from the template and input packages, and
+       // type info for the synthesized ASTs too.  This saves us
+       // having to book-keep where each ast.Node originated as we
+       // construct the resulting hybrid AST.
+       tr.info = &types.Info{
+               Types:      make(map[ast.Expr]types.TypeAndValue),
+               Defs:       make(map[*ast.Ident]types.Object),
+               Uses:       make(map[*ast.Ident]types.Object),
+               Selections: make(map[*ast.SelectorExpr]*types.Selection),
+       }
+       mergeTypeInfo(tr.info, tmplInfo)
+
+       // Compute set of imported objects required by after().
+       // TODO(adonovan): reject dot-imports in pattern
+       ast.Inspect(after, func(n ast.Node) bool {
+               if n, ok := n.(*ast.SelectorExpr); ok {
+                       if _, ok := tr.info.Selections[n]; !ok {
+                               // qualified ident
+                               obj := tr.info.Uses[n.Sel]
+                               tr.importedObjs[obj] = n
+                               return false // prune
+                       }
+               }
+               return true // recur
+       })
+
+       return tr, nil
+}
+
+// WriteAST is a convenience function that writes AST f to the specified file.
+func WriteAST(fset *token.FileSet, filename string, f *ast.File) (err error) {
+       fh, err := os.Create(filename)
+       if err != nil {
+               return err
+       }
+
+       defer func() {
+               if err2 := fh.Close(); err != nil {
+                       err = err2 // prefer earlier error
+               }
+       }()
+       return format.Node(fh, fset, f)
+}
+
+// -- utilities --------------------------------------------------------
+
+// funcSig returns the signature of the specified package-level function.
+func funcSig(pkg *types.Package, name string) *types.Signature {
+       if f, ok := pkg.Scope().Lookup(name).(*types.Func); ok {
+               return f.Type().(*types.Signature)
+       }
+       return nil
+}
+
+// soleExpr returns the sole expression in the before/after template function.
+func soleExpr(fn *ast.FuncDecl) (ast.Expr, error) {
+       if fn.Body == nil {
+               return nil, fmt.Errorf("no body")
+       }
+       if len(fn.Body.List) != 1 {
+               return nil, fmt.Errorf("must contain a single statement")
+       }
+       switch stmt := fn.Body.List[0].(type) {
+       case *ast.ReturnStmt:
+               if len(stmt.Results) != 1 {
+                       return nil, fmt.Errorf("return statement must have a single operand")
+               }
+               return stmt.Results[0], nil
+
+       case *ast.ExprStmt:
+               return stmt.X, nil
+       }
+
+       return nil, fmt.Errorf("must contain a single return or expression statement")
+}
+
+// stmtAndExpr returns the expression in the last return statement as well as the preceding lines.
+func stmtAndExpr(fn *ast.FuncDecl) ([]ast.Stmt, ast.Expr, error) {
+       if fn.Body == nil {
+               return nil, nil, fmt.Errorf("no body")
+       }
+
+       n := len(fn.Body.List)
+       if n == 0 {
+               return nil, nil, fmt.Errorf("must contain at least one statement")
+       }
+
+       stmts, last := fn.Body.List[:n-1], fn.Body.List[n-1]
+
+       switch last := last.(type) {
+       case *ast.ReturnStmt:
+               if len(last.Results) != 1 {
+                       return nil, nil, fmt.Errorf("return statement must have a single operand")
+               }
+               return stmts, last.Results[0], nil
+
+       case *ast.ExprStmt:
+               return stmts, last.X, nil
+       }
+
+       return nil, nil, fmt.Errorf("must end with a single return or expression statement")
+}
+
+// mergeTypeInfo adds type info from src to dst.
+func mergeTypeInfo(dst, src *types.Info) {
+       for k, v := range src.Types {
+               dst.Types[k] = v
+       }
+       for k, v := range src.Defs {
+               dst.Defs[k] = v
+       }
+       for k, v := range src.Uses {
+               dst.Uses[k] = v
+       }
+       for k, v := range src.Selections {
+               dst.Selections[k] = v
+       }
+}
+
+// (debugging only)
+func astString(fset *token.FileSet, n ast.Node) string {
+       var buf bytes.Buffer
+       printer.Fprint(&buf, fset, n)
+       return buf.String()
+}