gitee.com/wgliang/goreporter@v0.0.0-20180902115603-df1b20f7c5d0/linters/simpler/ssa/source.go (about)

     1  // Copyright 2013 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 ssa
     8  
     9  // This file defines utilities for working with source positions
    10  // or source-level named entities ("objects").
    11  
    12  // TODO(adonovan): test that {Value,Instruction}.Pos() positions match
    13  // the originating syntax, as specified.
    14  
    15  import (
    16  	"go/ast"
    17  	"go/token"
    18  	"go/types"
    19  	"log"
    20  )
    21  
    22  // EnclosingFunction returns the function that contains the syntax
    23  // node denoted by path.
    24  //
    25  // Syntax associated with package-level variable specifications is
    26  // enclosed by the package's init() function.
    27  //
    28  // Returns nil if not found; reasons might include:
    29  //    - the node is not enclosed by any function.
    30  //    - the node is within an anonymous function (FuncLit) and
    31  //      its SSA function has not been created yet
    32  //      (pkg.Build() has not yet been called).
    33  //
    34  func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
    35  	// Start with package-level function...
    36  	fn := findEnclosingPackageLevelFunction(pkg, path)
    37  	if fn == nil {
    38  		return nil // not in any function
    39  	}
    40  
    41  	// ...then walk down the nested anonymous functions.
    42  	n := len(path)
    43  outer:
    44  	for i := range path {
    45  		if lit, ok := path[n-1-i].(*ast.FuncLit); ok {
    46  			for _, anon := range fn.AnonFuncs {
    47  				if anon.Pos() == lit.Type.Func {
    48  					fn = anon
    49  					continue outer
    50  				}
    51  			}
    52  			// SSA function not found:
    53  			// - package not yet built, or maybe
    54  			// - builder skipped FuncLit in dead block
    55  			//   (in principle; but currently the Builder
    56  			//   generates even dead FuncLits).
    57  			return nil
    58  		}
    59  	}
    60  	return fn
    61  }
    62  
    63  // HasEnclosingFunction returns true if the AST node denoted by path
    64  // is contained within the declaration of some function or
    65  // package-level variable.
    66  //
    67  // Unlike EnclosingFunction, the behaviour of this function does not
    68  // depend on whether SSA code for pkg has been built, so it can be
    69  // used to quickly reject check inputs that will cause
    70  // EnclosingFunction to fail, prior to SSA building.
    71  //
    72  func HasEnclosingFunction(pkg *Package, path []ast.Node) bool {
    73  	return findEnclosingPackageLevelFunction(pkg, path) != nil
    74  }
    75  
    76  // findEnclosingPackageLevelFunction returns the Function
    77  // corresponding to the package-level function enclosing path.
    78  //
    79  func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function {
    80  	if n := len(path); n >= 2 { // [... {Gen,Func}Decl File]
    81  		switch decl := path[n-2].(type) {
    82  		case *ast.GenDecl:
    83  			if decl.Tok == token.VAR && n >= 3 {
    84  				// Package-level 'var' initializer.
    85  				return pkg.init
    86  			}
    87  
    88  		case *ast.FuncDecl:
    89  			if decl.Recv == nil && decl.Name.Name == "init" {
    90  				// Explicit init() function.
    91  				for _, b := range pkg.init.Blocks {
    92  					for _, instr := range b.Instrs {
    93  						if instr, ok := instr.(*Call); ok {
    94  							if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos {
    95  								return callee
    96  							}
    97  						}
    98  					}
    99  				}
   100  				// Hack: return non-nil when SSA is not yet
   101  				// built so that HasEnclosingFunction works.
   102  				return pkg.init
   103  			}
   104  			// Declared function/method.
   105  			return findNamedFunc(pkg, decl.Name.NamePos)
   106  		}
   107  	}
   108  	return nil // not in any function
   109  }
   110  
   111  // findNamedFunc returns the named function whose FuncDecl.Ident is at
   112  // position pos.
   113  //
   114  func findNamedFunc(pkg *Package, pos token.Pos) *Function {
   115  	// Look at all package members and method sets of named types.
   116  	// Not very efficient.
   117  	for _, mem := range pkg.Members {
   118  		switch mem := mem.(type) {
   119  		case *Function:
   120  			if mem.Pos() == pos {
   121  				return mem
   122  			}
   123  		case *Type:
   124  			mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
   125  			for i, n := 0, mset.Len(); i < n; i++ {
   126  				// Don't call Program.Method: avoid creating wrappers.
   127  				obj := mset.At(i).Obj().(*types.Func)
   128  				if obj.Pos() == pos {
   129  					if pkg.values[obj] == nil {
   130  						log.Println(obj)
   131  					}
   132  					return pkg.values[obj].(*Function)
   133  				}
   134  			}
   135  		}
   136  	}
   137  	return nil
   138  }
   139  
   140  // ValueForExpr returns the SSA Value that corresponds to non-constant
   141  // expression e.
   142  //
   143  // It returns nil if no value was found, e.g.
   144  //    - the expression is not lexically contained within f;
   145  //    - f was not built with debug information; or
   146  //    - e is a constant expression.  (For efficiency, no debug
   147  //      information is stored for constants. Use
   148  //      go/types.Info.Types[e].Value instead.)
   149  //    - e is a reference to nil or a built-in function.
   150  //    - the value was optimised away.
   151  //
   152  // If e is an addressable expression used in an lvalue context,
   153  // value is the address denoted by e, and isAddr is true.
   154  //
   155  // The types of e (or &e, if isAddr) and the result are equal
   156  // (modulo "untyped" bools resulting from comparisons).
   157  //
   158  // (Tip: to find the ssa.Value given a source position, use
   159  // importer.PathEnclosingInterval to locate the ast.Node, then
   160  // EnclosingFunction to locate the Function, then ValueForExpr to find
   161  // the ssa.Value.)
   162  //
   163  func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) {
   164  	if f.debugInfo() { // (opt)
   165  		e = unparen(e)
   166  		for _, b := range f.Blocks {
   167  			for _, instr := range b.Instrs {
   168  				if ref, ok := instr.(*DebugRef); ok {
   169  					if ref.Expr == e {
   170  						return ref.X, ref.IsAddr
   171  					}
   172  				}
   173  			}
   174  		}
   175  	}
   176  	return
   177  }
   178  
   179  // --- Lookup functions for source-level named entities (types.Objects) ---
   180  
   181  // Package returns the SSA Package corresponding to the specified
   182  // type-checker package object.
   183  // It returns nil if no such SSA package has been created.
   184  //
   185  func (prog *Program) Package(obj *types.Package) *Package {
   186  	return prog.packages[obj]
   187  }
   188  
   189  // packageLevelValue returns the package-level value corresponding to
   190  // the specified named object, which may be a package-level const
   191  // (*Const), var (*Global) or func (*Function) of some package in
   192  // prog.  It returns nil if the object is not found.
   193  //
   194  func (prog *Program) packageLevelValue(obj types.Object) Value {
   195  	if pkg, ok := prog.packages[obj.Pkg()]; ok {
   196  		return pkg.values[obj]
   197  	}
   198  	return nil
   199  }
   200  
   201  // FuncValue returns the concrete Function denoted by the source-level
   202  // named function obj, or nil if obj denotes an interface method.
   203  //
   204  // TODO(adonovan): check the invariant that obj.Type() matches the
   205  // result's Signature, both in the params/results and in the receiver.
   206  //
   207  func (prog *Program) FuncValue(obj *types.Func) *Function {
   208  	fn, _ := prog.packageLevelValue(obj).(*Function)
   209  	return fn
   210  }
   211  
   212  // ConstValue returns the SSA Value denoted by the source-level named
   213  // constant obj.
   214  //
   215  func (prog *Program) ConstValue(obj *types.Const) *Const {
   216  	// TODO(adonovan): opt: share (don't reallocate)
   217  	// Consts for const objects and constant ast.Exprs.
   218  
   219  	// Universal constant? {true,false,nil}
   220  	if obj.Parent() == types.Universe {
   221  		return NewConst(obj.Val(), obj.Type())
   222  	}
   223  	// Package-level named constant?
   224  	if v := prog.packageLevelValue(obj); v != nil {
   225  		return v.(*Const)
   226  	}
   227  	return NewConst(obj.Val(), obj.Type())
   228  }
   229  
   230  // VarValue returns the SSA Value that corresponds to a specific
   231  // identifier denoting the source-level named variable obj.
   232  //
   233  // VarValue returns nil if a local variable was not found, perhaps
   234  // because its package was not built, the debug information was not
   235  // requested during SSA construction, or the value was optimized away.
   236  //
   237  // ref is the path to an ast.Ident (e.g. from PathEnclosingInterval),
   238  // and that ident must resolve to obj.
   239  //
   240  // pkg is the package enclosing the reference.  (A reference to a var
   241  // always occurs within a function, so we need to know where to find it.)
   242  //
   243  // If the identifier is a field selector and its base expression is
   244  // non-addressable, then VarValue returns the value of that field.
   245  // For example:
   246  //    func f() struct {x int}
   247  //    f().x  // VarValue(x) returns a *Field instruction of type int
   248  //
   249  // All other identifiers denote addressable locations (variables).
   250  // For them, VarValue may return either the variable's address or its
   251  // value, even when the expression is evaluated only for its value; the
   252  // situation is reported by isAddr, the second component of the result.
   253  //
   254  // If !isAddr, the returned value is the one associated with the
   255  // specific identifier.  For example,
   256  //       var x int    // VarValue(x) returns Const 0 here
   257  //       x = 1        // VarValue(x) returns Const 1 here
   258  //
   259  // It is not specified whether the value or the address is returned in
   260  // any particular case, as it may depend upon optimizations performed
   261  // during SSA code generation, such as registerization, constant
   262  // folding, avoidance of materialization of subexpressions, etc.
   263  //
   264  func (prog *Program) VarValue(obj *types.Var, pkg *Package, ref []ast.Node) (value Value, isAddr bool) {
   265  	// All references to a var are local to some function, possibly init.
   266  	fn := EnclosingFunction(pkg, ref)
   267  	if fn == nil {
   268  		return // e.g. def of struct field; SSA not built?
   269  	}
   270  
   271  	id := ref[0].(*ast.Ident)
   272  
   273  	// Defining ident of a parameter?
   274  	if id.Pos() == obj.Pos() {
   275  		for _, param := range fn.Params {
   276  			if param.Object() == obj {
   277  				return param, false
   278  			}
   279  		}
   280  	}
   281  
   282  	// Other ident?
   283  	for _, b := range fn.Blocks {
   284  		for _, instr := range b.Instrs {
   285  			if dr, ok := instr.(*DebugRef); ok {
   286  				if dr.Pos() == id.Pos() {
   287  					return dr.X, dr.IsAddr
   288  				}
   289  			}
   290  		}
   291  	}
   292  
   293  	// Defining ident of package-level var?
   294  	if v := prog.packageLevelValue(obj); v != nil {
   295  		return v.(*Global), true
   296  	}
   297  
   298  	return // e.g. debug info not requested, or var optimized away
   299  }