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