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 = ast.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 if 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