github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/refactor/eg/rewrite14.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 // This file defines the AST rewriting pass. 10 // Most of it was plundered directly from 11 // $GOROOT/src/cmd/gofmt/rewrite.go (after convergent evolution). 12 13 import ( 14 "fmt" 15 "go/ast" 16 "go/token" 17 "os" 18 "reflect" 19 "sort" 20 "strconv" 21 "strings" 22 23 "golang.org/x/tools/go/ast/astutil" 24 "golang.org/x/tools/go/types" 25 ) 26 27 // Transform applies the transformation to the specified parsed file, 28 // whose type information is supplied in info, and returns the number 29 // of replacements that were made. 30 // 31 // It mutates the AST in place (the identity of the root node is 32 // unchanged), and may add nodes for which no type information is 33 // available in info. 34 // 35 // Derived from rewriteFile in $GOROOT/src/cmd/gofmt/rewrite.go. 36 // 37 func (tr *Transformer) Transform(info *types.Info, pkg *types.Package, file *ast.File) int { 38 if !tr.seenInfos[info] { 39 tr.seenInfos[info] = true 40 mergeTypeInfo(tr.info, info) 41 } 42 tr.currentPkg = pkg 43 tr.nsubsts = 0 44 45 if tr.verbose { 46 fmt.Fprintf(os.Stderr, "before: %s\n", astString(tr.fset, tr.before)) 47 fmt.Fprintf(os.Stderr, "after: %s\n", astString(tr.fset, tr.after)) 48 } 49 50 var f func(rv reflect.Value) reflect.Value 51 f = func(rv reflect.Value) reflect.Value { 52 // don't bother if val is invalid to start with 53 if !rv.IsValid() { 54 return reflect.Value{} 55 } 56 57 rv = apply(f, rv) 58 59 e := rvToExpr(rv) 60 if e != nil { 61 savedEnv := tr.env 62 tr.env = make(map[string]ast.Expr) // inefficient! Use a slice of k/v pairs 63 64 if tr.matchExpr(tr.before, e) { 65 if tr.verbose { 66 fmt.Fprintf(os.Stderr, "%s matches %s", 67 astString(tr.fset, tr.before), astString(tr.fset, e)) 68 if len(tr.env) > 0 { 69 fmt.Fprintf(os.Stderr, " with:") 70 for name, ast := range tr.env { 71 fmt.Fprintf(os.Stderr, " %s->%s", 72 name, astString(tr.fset, ast)) 73 } 74 } 75 fmt.Fprintf(os.Stderr, "\n") 76 } 77 tr.nsubsts++ 78 79 // Clone the replacement tree, performing parameter substitution. 80 // We update all positions to n.Pos() to aid comment placement. 81 rv = tr.subst(tr.env, reflect.ValueOf(tr.after), 82 reflect.ValueOf(e.Pos())) 83 } 84 tr.env = savedEnv 85 } 86 87 return rv 88 } 89 file2 := apply(f, reflect.ValueOf(file)).Interface().(*ast.File) 90 91 // By construction, the root node is unchanged. 92 if file != file2 { 93 panic("BUG") 94 } 95 96 // Add any necessary imports. 97 // TODO(adonovan): remove no-longer needed imports too. 98 if tr.nsubsts > 0 { 99 pkgs := make(map[string]*types.Package) 100 for obj := range tr.importedObjs { 101 pkgs[obj.Pkg().Path()] = obj.Pkg() 102 } 103 104 for _, imp := range file.Imports { 105 path, _ := strconv.Unquote(imp.Path.Value) 106 delete(pkgs, path) 107 } 108 delete(pkgs, pkg.Path()) // don't import self 109 110 // NB: AddImport may completely replace the AST! 111 // It thus renders info and tr.info no longer relevant to file. 112 var paths []string 113 for path := range pkgs { 114 paths = append(paths, path) 115 } 116 sort.Strings(paths) 117 for _, path := range paths { 118 astutil.AddImport(tr.fset, file, path) 119 } 120 } 121 122 tr.currentPkg = nil 123 124 return tr.nsubsts 125 } 126 127 // setValue is a wrapper for x.SetValue(y); it protects 128 // the caller from panics if x cannot be changed to y. 129 func setValue(x, y reflect.Value) { 130 // don't bother if y is invalid to start with 131 if !y.IsValid() { 132 return 133 } 134 defer func() { 135 if x := recover(); x != nil { 136 if s, ok := x.(string); ok && 137 (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) { 138 // x cannot be set to y - ignore this rewrite 139 return 140 } 141 panic(x) 142 } 143 }() 144 x.Set(y) 145 } 146 147 // Values/types for special cases. 148 var ( 149 objectPtrNil = reflect.ValueOf((*ast.Object)(nil)) 150 scopePtrNil = reflect.ValueOf((*ast.Scope)(nil)) 151 152 identType = reflect.TypeOf((*ast.Ident)(nil)) 153 selectorExprType = reflect.TypeOf((*ast.SelectorExpr)(nil)) 154 objectPtrType = reflect.TypeOf((*ast.Object)(nil)) 155 positionType = reflect.TypeOf(token.NoPos) 156 callExprType = reflect.TypeOf((*ast.CallExpr)(nil)) 157 scopePtrType = reflect.TypeOf((*ast.Scope)(nil)) 158 ) 159 160 // apply replaces each AST field x in val with f(x), returning val. 161 // To avoid extra conversions, f operates on the reflect.Value form. 162 func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value { 163 if !val.IsValid() { 164 return reflect.Value{} 165 } 166 167 // *ast.Objects introduce cycles and are likely incorrect after 168 // rewrite; don't follow them but replace with nil instead 169 if val.Type() == objectPtrType { 170 return objectPtrNil 171 } 172 173 // similarly for scopes: they are likely incorrect after a rewrite; 174 // replace them with nil 175 if val.Type() == scopePtrType { 176 return scopePtrNil 177 } 178 179 switch v := reflect.Indirect(val); v.Kind() { 180 case reflect.Slice: 181 for i := 0; i < v.Len(); i++ { 182 e := v.Index(i) 183 setValue(e, f(e)) 184 } 185 case reflect.Struct: 186 for i := 0; i < v.NumField(); i++ { 187 e := v.Field(i) 188 setValue(e, f(e)) 189 } 190 case reflect.Interface: 191 e := v.Elem() 192 setValue(v, f(e)) 193 } 194 return val 195 } 196 197 // subst returns a copy of (replacement) pattern with values from env 198 // substituted in place of wildcards and pos used as the position of 199 // tokens from the pattern. if env == nil, subst returns a copy of 200 // pattern and doesn't change the line number information. 201 func (tr *Transformer) subst(env map[string]ast.Expr, pattern, pos reflect.Value) reflect.Value { 202 if !pattern.IsValid() { 203 return reflect.Value{} 204 } 205 206 // *ast.Objects introduce cycles and are likely incorrect after 207 // rewrite; don't follow them but replace with nil instead 208 if pattern.Type() == objectPtrType { 209 return objectPtrNil 210 } 211 212 // similarly for scopes: they are likely incorrect after a rewrite; 213 // replace them with nil 214 if pattern.Type() == scopePtrType { 215 return scopePtrNil 216 } 217 218 // Wildcard gets replaced with map value. 219 if env != nil && pattern.Type() == identType { 220 id := pattern.Interface().(*ast.Ident) 221 if old, ok := env[id.Name]; ok { 222 return tr.subst(nil, reflect.ValueOf(old), reflect.Value{}) 223 } 224 } 225 226 // Emit qualified identifiers in the pattern by appropriate 227 // (possibly qualified) identifier in the input. 228 // 229 // The template cannot contain dot imports, so all identifiers 230 // for imported objects are explicitly qualified. 231 // 232 // We assume (unsoundly) that there are no dot or named 233 // imports in the input code, nor are any imported package 234 // names shadowed, so the usual normal qualified identifier 235 // syntax may be used. 236 // TODO(adonovan): fix: avoid this assumption. 237 // 238 // A refactoring may be applied to a package referenced by the 239 // template. Objects belonging to the current package are 240 // denoted by unqualified identifiers. 241 // 242 if tr.importedObjs != nil && pattern.Type() == selectorExprType { 243 obj := isRef(pattern.Interface().(*ast.SelectorExpr), tr.info) 244 if obj != nil { 245 if sel, ok := tr.importedObjs[obj]; ok { 246 var id ast.Expr 247 if obj.Pkg() == tr.currentPkg { 248 id = sel.Sel // unqualified 249 } else { 250 id = sel // pkg-qualified 251 } 252 253 // Return a clone of id. 254 saved := tr.importedObjs 255 tr.importedObjs = nil // break cycle 256 r := tr.subst(nil, reflect.ValueOf(id), pos) 257 tr.importedObjs = saved 258 return r 259 } 260 } 261 } 262 263 if pos.IsValid() && pattern.Type() == positionType { 264 // use new position only if old position was valid in the first place 265 if old := pattern.Interface().(token.Pos); !old.IsValid() { 266 return pattern 267 } 268 return pos 269 } 270 271 // Otherwise copy. 272 switch p := pattern; p.Kind() { 273 case reflect.Slice: 274 v := reflect.MakeSlice(p.Type(), p.Len(), p.Len()) 275 for i := 0; i < p.Len(); i++ { 276 v.Index(i).Set(tr.subst(env, p.Index(i), pos)) 277 } 278 return v 279 280 case reflect.Struct: 281 v := reflect.New(p.Type()).Elem() 282 for i := 0; i < p.NumField(); i++ { 283 v.Field(i).Set(tr.subst(env, p.Field(i), pos)) 284 } 285 return v 286 287 case reflect.Ptr: 288 v := reflect.New(p.Type()).Elem() 289 if elem := p.Elem(); elem.IsValid() { 290 v.Set(tr.subst(env, elem, pos).Addr()) 291 } 292 293 // Duplicate type information for duplicated ast.Expr. 294 // All ast.Node implementations are *structs, 295 // so this case catches them all. 296 if e := rvToExpr(v); e != nil { 297 updateTypeInfo(tr.info, e, p.Interface().(ast.Expr)) 298 } 299 return v 300 301 case reflect.Interface: 302 v := reflect.New(p.Type()).Elem() 303 if elem := p.Elem(); elem.IsValid() { 304 v.Set(tr.subst(env, elem, pos)) 305 } 306 return v 307 } 308 309 return pattern 310 } 311 312 // -- utilities ------------------------------------------------------- 313 314 func rvToExpr(rv reflect.Value) ast.Expr { 315 if rv.CanInterface() { 316 if e, ok := rv.Interface().(ast.Expr); ok { 317 return e 318 } 319 } 320 return nil 321 } 322 323 // updateTypeInfo duplicates type information for the existing AST old 324 // so that it also applies to duplicated AST new. 325 func updateTypeInfo(info *types.Info, new, old ast.Expr) { 326 switch new := new.(type) { 327 case *ast.Ident: 328 orig := old.(*ast.Ident) 329 if obj, ok := info.Defs[orig]; ok { 330 info.Defs[new] = obj 331 } 332 if obj, ok := info.Uses[orig]; ok { 333 info.Uses[new] = obj 334 } 335 336 case *ast.SelectorExpr: 337 orig := old.(*ast.SelectorExpr) 338 if sel, ok := info.Selections[orig]; ok { 339 info.Selections[new] = sel 340 } 341 } 342 343 if tv, ok := info.Types[old]; ok { 344 info.Types[new] = tv 345 } 346 }