github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/refactor/eg/match.go (about) 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 // +build go1.5 6 7 package eg 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/token" 13 "go/types" 14 "log" 15 "os" 16 "reflect" 17 18 "golang.org/x/tools/go/ast/astutil" 19 "golang.org/x/tools/go/exact" 20 ) 21 22 // matchExpr reports whether pattern x matches y. 23 // 24 // If tr.allowWildcards, Idents in x that refer to parameters are 25 // treated as wildcards, and match any y that is assignable to the 26 // parameter type; matchExpr records this correspondence in tr.env. 27 // Otherwise, matchExpr simply reports whether the two trees are 28 // equivalent. 29 // 30 // A wildcard appearing more than once in the pattern must 31 // consistently match the same tree. 32 // 33 func (tr *Transformer) matchExpr(x, y ast.Expr) bool { 34 if x == nil && y == nil { 35 return true 36 } 37 if x == nil || y == nil { 38 return false 39 } 40 x = unparen(x) 41 y = unparen(y) 42 43 // Is x a wildcard? (a reference to a 'before' parameter) 44 if xobj, ok := tr.wildcardObj(x); ok { 45 return tr.matchWildcard(xobj, y) 46 } 47 48 // Object identifiers (including pkg-qualified ones) 49 // are handled semantically, not syntactically. 50 xobj := isRef(x, tr.info) 51 yobj := isRef(y, tr.info) 52 if xobj != nil { 53 return xobj == yobj 54 } 55 if yobj != nil { 56 return false 57 } 58 59 // TODO(adonovan): audit: we cannot assume these ast.Exprs 60 // contain non-nil pointers. e.g. ImportSpec.Name may be a 61 // nil *ast.Ident. 62 63 if reflect.TypeOf(x) != reflect.TypeOf(y) { 64 return false 65 } 66 switch x := x.(type) { 67 case *ast.Ident: 68 log.Fatalf("unexpected Ident: %s", astString(tr.fset, x)) 69 70 case *ast.BasicLit: 71 y := y.(*ast.BasicLit) 72 xval := exact.MakeFromLiteral(x.Value, x.Kind) 73 yval := exact.MakeFromLiteral(y.Value, y.Kind) 74 return exact.Compare(xval, token.EQL, yval) 75 76 case *ast.FuncLit: 77 // func literals (and thus statement syntax) never match. 78 return false 79 80 case *ast.CompositeLit: 81 y := y.(*ast.CompositeLit) 82 return (x.Type == nil) == (y.Type == nil) && 83 (x.Type == nil || tr.matchType(x.Type, y.Type)) && 84 tr.matchExprs(x.Elts, y.Elts) 85 86 case *ast.SelectorExpr: 87 y := y.(*ast.SelectorExpr) 88 return tr.matchSelectorExpr(x, y) && 89 tr.info.Selections[x].Obj() == tr.info.Selections[y].Obj() 90 91 case *ast.IndexExpr: 92 y := y.(*ast.IndexExpr) 93 return tr.matchExpr(x.X, y.X) && 94 tr.matchExpr(x.Index, y.Index) 95 96 case *ast.SliceExpr: 97 y := y.(*ast.SliceExpr) 98 return tr.matchExpr(x.X, y.X) && 99 tr.matchExpr(x.Low, y.Low) && 100 tr.matchExpr(x.High, y.High) && 101 tr.matchExpr(x.Max, y.Max) && 102 x.Slice3 == y.Slice3 103 104 case *ast.TypeAssertExpr: 105 y := y.(*ast.TypeAssertExpr) 106 return tr.matchExpr(x.X, y.X) && 107 tr.matchType(x.Type, y.Type) 108 109 case *ast.CallExpr: 110 y := y.(*ast.CallExpr) 111 match := tr.matchExpr // function call 112 if tr.info.Types[x.Fun].IsType() { 113 match = tr.matchType // type conversion 114 } 115 return x.Ellipsis.IsValid() == y.Ellipsis.IsValid() && 116 match(x.Fun, y.Fun) && 117 tr.matchExprs(x.Args, y.Args) 118 119 case *ast.StarExpr: 120 y := y.(*ast.StarExpr) 121 return tr.matchExpr(x.X, y.X) 122 123 case *ast.UnaryExpr: 124 y := y.(*ast.UnaryExpr) 125 return x.Op == y.Op && 126 tr.matchExpr(x.X, y.X) 127 128 case *ast.BinaryExpr: 129 y := y.(*ast.BinaryExpr) 130 return x.Op == y.Op && 131 tr.matchExpr(x.X, y.X) && 132 tr.matchExpr(x.Y, y.Y) 133 134 case *ast.KeyValueExpr: 135 y := y.(*ast.KeyValueExpr) 136 return tr.matchExpr(x.Key, y.Key) && 137 tr.matchExpr(x.Value, y.Value) 138 } 139 140 panic(fmt.Sprintf("unhandled AST node type: %T", x)) 141 } 142 143 func (tr *Transformer) matchExprs(xx, yy []ast.Expr) bool { 144 if len(xx) != len(yy) { 145 return false 146 } 147 for i := range xx { 148 if !tr.matchExpr(xx[i], yy[i]) { 149 return false 150 } 151 } 152 return true 153 } 154 155 // matchType reports whether the two type ASTs denote identical types. 156 func (tr *Transformer) matchType(x, y ast.Expr) bool { 157 tx := tr.info.Types[x].Type 158 ty := tr.info.Types[y].Type 159 return types.Identical(tx, ty) 160 } 161 162 func (tr *Transformer) wildcardObj(x ast.Expr) (*types.Var, bool) { 163 if x, ok := x.(*ast.Ident); ok && x != nil && tr.allowWildcards { 164 if xobj, ok := tr.info.Uses[x].(*types.Var); ok && tr.wildcards[xobj] { 165 return xobj, true 166 } 167 } 168 return nil, false 169 } 170 171 func (tr *Transformer) matchSelectorExpr(x, y *ast.SelectorExpr) bool { 172 if xobj, ok := tr.wildcardObj(x.X); ok { 173 field := x.Sel.Name 174 yt := tr.info.TypeOf(y.X) 175 o, _, _ := types.LookupFieldOrMethod(yt, true, tr.currentPkg, field) 176 if o != nil { 177 tr.env[xobj.Name()] = y.X // record binding 178 return true 179 } 180 } 181 return tr.matchExpr(x.X, y.X) 182 } 183 184 func (tr *Transformer) matchWildcard(xobj *types.Var, y ast.Expr) bool { 185 name := xobj.Name() 186 187 if tr.verbose { 188 fmt.Fprintf(os.Stderr, "%s: wildcard %s -> %s?: ", 189 tr.fset.Position(y.Pos()), name, astString(tr.fset, y)) 190 } 191 192 // Check that y is assignable to the declared type of the param. 193 yt := tr.info.TypeOf(y) 194 if yt == nil { 195 // y has no type. 196 // Perhaps it is an *ast.Ellipsis in [...]T{}, or 197 // an *ast.KeyValueExpr in T{k: v}. 198 // Clearly these pseudo-expressions cannot match a 199 // wildcard, but it would nice if we had a way to ignore 200 // the difference between T{v} and T{k:v} for structs. 201 return false 202 } 203 if !types.AssignableTo(yt, xobj.Type()) { 204 if tr.verbose { 205 fmt.Fprintf(os.Stderr, "%s not assignable to %s\n", yt, xobj.Type()) 206 } 207 return false 208 } 209 210 // A wildcard matches any expression. 211 // If it appears multiple times in the pattern, it must match 212 // the same expression each time. 213 if old, ok := tr.env[name]; ok { 214 // found existing binding 215 tr.allowWildcards = false 216 r := tr.matchExpr(old, y) 217 if tr.verbose { 218 fmt.Fprintf(os.Stderr, "%t secondary match, primary was %s\n", 219 r, astString(tr.fset, old)) 220 } 221 tr.allowWildcards = true 222 return r 223 } 224 225 if tr.verbose { 226 fmt.Fprintf(os.Stderr, "primary match\n") 227 } 228 229 tr.env[name] = y // record binding 230 return true 231 } 232 233 // -- utilities -------------------------------------------------------- 234 235 func unparen(e ast.Expr) ast.Expr { return astutil.Unparen(e) } 236 237 // isRef returns the object referred to by this (possibly qualified) 238 // identifier, or nil if the node is not a referring identifier. 239 func isRef(n ast.Node, info *types.Info) types.Object { 240 switch n := n.(type) { 241 case *ast.Ident: 242 return info.Uses[n] 243 244 case *ast.SelectorExpr: 245 if _, ok := info.Selections[n]; !ok { 246 // qualified ident 247 return info.Uses[n.Sel] 248 } 249 } 250 return nil 251 }