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