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