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 }