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  }