Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / refactor / eg / match.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/refactor/eg/match.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/refactor/eg/match.go
new file mode 100644 (file)
index 0000000..89c0f8d
--- /dev/null
@@ -0,0 +1,249 @@
+// 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
+
+import (
+       "fmt"
+       "go/ast"
+       "go/constant"
+       "go/token"
+       "go/types"
+       "log"
+       "os"
+       "reflect"
+
+       "golang.org/x/tools/go/ast/astutil"
+)
+
+// matchExpr reports whether pattern x matches y.
+//
+// If tr.allowWildcards, Idents in x that refer to parameters are
+// treated as wildcards, and match any y that is assignable to the
+// parameter type; matchExpr records this correspondence in tr.env.
+// Otherwise, matchExpr simply reports whether the two trees are
+// equivalent.
+//
+// A wildcard appearing more than once in the pattern must
+// consistently match the same tree.
+//
+func (tr *Transformer) matchExpr(x, y ast.Expr) bool {
+       if x == nil && y == nil {
+               return true
+       }
+       if x == nil || y == nil {
+               return false
+       }
+       x = unparen(x)
+       y = unparen(y)
+
+       // Is x a wildcard?  (a reference to a 'before' parameter)
+       if xobj, ok := tr.wildcardObj(x); ok {
+               return tr.matchWildcard(xobj, y)
+       }
+
+       // Object identifiers (including pkg-qualified ones)
+       // are handled semantically, not syntactically.
+       xobj := isRef(x, tr.info)
+       yobj := isRef(y, tr.info)
+       if xobj != nil {
+               return xobj == yobj
+       }
+       if yobj != nil {
+               return false
+       }
+
+       // TODO(adonovan): audit: we cannot assume these ast.Exprs
+       // contain non-nil pointers.  e.g. ImportSpec.Name may be a
+       // nil *ast.Ident.
+
+       if reflect.TypeOf(x) != reflect.TypeOf(y) {
+               return false
+       }
+       switch x := x.(type) {
+       case *ast.Ident:
+               log.Fatalf("unexpected Ident: %s", astString(tr.fset, x))
+
+       case *ast.BasicLit:
+               y := y.(*ast.BasicLit)
+               xval := constant.MakeFromLiteral(x.Value, x.Kind, 0)
+               yval := constant.MakeFromLiteral(y.Value, y.Kind, 0)
+               return constant.Compare(xval, token.EQL, yval)
+
+       case *ast.FuncLit:
+               // func literals (and thus statement syntax) never match.
+               return false
+
+       case *ast.CompositeLit:
+               y := y.(*ast.CompositeLit)
+               return (x.Type == nil) == (y.Type == nil) &&
+                       (x.Type == nil || tr.matchType(x.Type, y.Type)) &&
+                       tr.matchExprs(x.Elts, y.Elts)
+
+       case *ast.SelectorExpr:
+               y := y.(*ast.SelectorExpr)
+               return tr.matchSelectorExpr(x, y) &&
+                       tr.info.Selections[x].Obj() == tr.info.Selections[y].Obj()
+
+       case *ast.IndexExpr:
+               y := y.(*ast.IndexExpr)
+               return tr.matchExpr(x.X, y.X) &&
+                       tr.matchExpr(x.Index, y.Index)
+
+       case *ast.SliceExpr:
+               y := y.(*ast.SliceExpr)
+               return tr.matchExpr(x.X, y.X) &&
+                       tr.matchExpr(x.Low, y.Low) &&
+                       tr.matchExpr(x.High, y.High) &&
+                       tr.matchExpr(x.Max, y.Max) &&
+                       x.Slice3 == y.Slice3
+
+       case *ast.TypeAssertExpr:
+               y := y.(*ast.TypeAssertExpr)
+               return tr.matchExpr(x.X, y.X) &&
+                       tr.matchType(x.Type, y.Type)
+
+       case *ast.CallExpr:
+               y := y.(*ast.CallExpr)
+               match := tr.matchExpr // function call
+               if tr.info.Types[x.Fun].IsType() {
+                       match = tr.matchType // type conversion
+               }
+               return x.Ellipsis.IsValid() == y.Ellipsis.IsValid() &&
+                       match(x.Fun, y.Fun) &&
+                       tr.matchExprs(x.Args, y.Args)
+
+       case *ast.StarExpr:
+               y := y.(*ast.StarExpr)
+               return tr.matchExpr(x.X, y.X)
+
+       case *ast.UnaryExpr:
+               y := y.(*ast.UnaryExpr)
+               return x.Op == y.Op &&
+                       tr.matchExpr(x.X, y.X)
+
+       case *ast.BinaryExpr:
+               y := y.(*ast.BinaryExpr)
+               return x.Op == y.Op &&
+                       tr.matchExpr(x.X, y.X) &&
+                       tr.matchExpr(x.Y, y.Y)
+
+       case *ast.KeyValueExpr:
+               y := y.(*ast.KeyValueExpr)
+               return tr.matchExpr(x.Key, y.Key) &&
+                       tr.matchExpr(x.Value, y.Value)
+       }
+
+       panic(fmt.Sprintf("unhandled AST node type: %T", x))
+}
+
+func (tr *Transformer) matchExprs(xx, yy []ast.Expr) bool {
+       if len(xx) != len(yy) {
+               return false
+       }
+       for i := range xx {
+               if !tr.matchExpr(xx[i], yy[i]) {
+                       return false
+               }
+       }
+       return true
+}
+
+// matchType reports whether the two type ASTs denote identical types.
+func (tr *Transformer) matchType(x, y ast.Expr) bool {
+       tx := tr.info.Types[x].Type
+       ty := tr.info.Types[y].Type
+       return types.Identical(tx, ty)
+}
+
+func (tr *Transformer) wildcardObj(x ast.Expr) (*types.Var, bool) {
+       if x, ok := x.(*ast.Ident); ok && x != nil && tr.allowWildcards {
+               if xobj, ok := tr.info.Uses[x].(*types.Var); ok && tr.wildcards[xobj] {
+                       return xobj, true
+               }
+       }
+       return nil, false
+}
+
+func (tr *Transformer) matchSelectorExpr(x, y *ast.SelectorExpr) bool {
+       if xobj, ok := tr.wildcardObj(x.X); ok {
+               field := x.Sel.Name
+               yt := tr.info.TypeOf(y.X)
+               o, _, _ := types.LookupFieldOrMethod(yt, true, tr.currentPkg, field)
+               if o != nil {
+                       tr.env[xobj.Name()] = y.X // record binding
+                       return true
+               }
+       }
+       return tr.matchExpr(x.X, y.X)
+}
+
+func (tr *Transformer) matchWildcard(xobj *types.Var, y ast.Expr) bool {
+       name := xobj.Name()
+
+       if tr.verbose {
+               fmt.Fprintf(os.Stderr, "%s: wildcard %s -> %s?: ",
+                       tr.fset.Position(y.Pos()), name, astString(tr.fset, y))
+       }
+
+       // Check that y is assignable to the declared type of the param.
+       yt := tr.info.TypeOf(y)
+       if yt == nil {
+               // y has no type.
+               // Perhaps it is an *ast.Ellipsis in [...]T{}, or
+               // an *ast.KeyValueExpr in T{k: v}.
+               // Clearly these pseudo-expressions cannot match a
+               // wildcard, but it would nice if we had a way to ignore
+               // the difference between T{v} and T{k:v} for structs.
+               return false
+       }
+       if !types.AssignableTo(yt, xobj.Type()) {
+               if tr.verbose {
+                       fmt.Fprintf(os.Stderr, "%s not assignable to %s\n", yt, xobj.Type())
+               }
+               return false
+       }
+
+       // A wildcard matches any expression.
+       // If it appears multiple times in the pattern, it must match
+       // the same expression each time.
+       if old, ok := tr.env[name]; ok {
+               // found existing binding
+               tr.allowWildcards = false
+               r := tr.matchExpr(old, y)
+               if tr.verbose {
+                       fmt.Fprintf(os.Stderr, "%t secondary match, primary was %s\n",
+                               r, astString(tr.fset, old))
+               }
+               tr.allowWildcards = true
+               return r
+       }
+
+       if tr.verbose {
+               fmt.Fprintf(os.Stderr, "primary match\n")
+       }
+
+       tr.env[name] = y // record binding
+       return true
+}
+
+// -- utilities --------------------------------------------------------
+
+func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) }
+
+// isRef returns the object referred to by this (possibly qualified)
+// identifier, or nil if the node is not a referring identifier.
+func isRef(n ast.Node, info *types.Info) types.Object {
+       switch n := n.(type) {
+       case *ast.Ident:
+               return info.Uses[n]
+
+       case *ast.SelectorExpr:
+               if _, ok := info.Selections[n]; !ok {
+                       // qualified ident
+                       return info.Uses[n.Sel]
+               }
+       }
+       return nil
+}