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  }