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 | "golang.org/x/tools/internal/typeparams" |
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 | 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 | func HasEnclosingFunction(pkg *Package, path []ast.Node) bool { |
70 | return findEnclosingPackageLevelFunction(pkg, path) != nil |
71 | } |
72 | |
73 | // findEnclosingPackageLevelFunction returns the Function |
74 | // corresponding to the package-level function enclosing path. |
75 | func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function { |
76 | if n := len(path); n >= 2 { // [... {Gen,Func}Decl File] |
77 | switch decl := path[n-2].(type) { |
78 | case *ast.GenDecl: |
79 | if decl.Tok == token.VAR && n >= 3 { |
80 | // Package-level 'var' initializer. |
81 | return pkg.init |
82 | } |
83 | |
84 | case *ast.FuncDecl: |
85 | if decl.Recv == nil && decl.Name.Name == "init" { |
86 | // Explicit init() function. |
87 | for _, b := range pkg.init.Blocks { |
88 | for _, instr := range b.Instrs { |
89 | if instr, ok := instr.(*Call); ok { |
90 | if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos { |
91 | return callee |
92 | } |
93 | } |
94 | } |
95 | } |
96 | // Hack: return non-nil when SSA is not yet |
97 | // built so that HasEnclosingFunction works. |
98 | return pkg.init |
99 | } |
100 | // Declared function/method. |
101 | return findNamedFunc(pkg, decl.Name.NamePos) |
102 | } |
103 | } |
104 | return nil // not in any function |
105 | } |
106 | |
107 | // findNamedFunc returns the named function whose FuncDecl.Ident is at |
108 | // position pos. |
109 | func findNamedFunc(pkg *Package, pos token.Pos) *Function { |
110 | // Look at all package members and method sets of named types. |
111 | // Not very efficient. |
112 | for _, mem := range pkg.Members { |
113 | switch mem := mem.(type) { |
114 | case *Function: |
115 | if mem.Pos() == pos { |
116 | return mem |
117 | } |
118 | case *Type: |
119 | mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type())) |
120 | for i, n := 0, mset.Len(); i < n; i++ { |
121 | // Don't call Program.Method: avoid creating wrappers. |
122 | obj := mset.At(i).Obj().(*types.Func) |
123 | if obj.Pos() == pos { |
124 | return pkg.objects[obj].(*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 object. |
174 | // It returns nil if no such SSA package has been created. |
175 | func (prog *Program) Package(obj *types.Package) *Package { |
176 | return prog.packages[obj] |
177 | } |
178 | |
179 | // packageLevelMember returns the package-level member corresponding to |
180 | // the specified named object, which may be a package-level const |
181 | // (*NamedConst), var (*Global) or func (*Function) of some package in |
182 | // prog. It returns nil if the object is not found. |
183 | func (prog *Program) packageLevelMember(obj types.Object) Member { |
184 | if pkg, ok := prog.packages[obj.Pkg()]; ok { |
185 | return pkg.objects[obj] |
186 | } |
187 | return nil |
188 | } |
189 | |
190 | // originFunc returns the package-level generic function that is the |
191 | // origin of obj. If returns nil if the generic function is not found. |
192 | func (prog *Program) originFunc(obj *types.Func) *Function { |
193 | return prog.declaredFunc(typeparams.OriginMethod(obj)) |
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 | func (prog *Program) FuncValue(obj *types.Func) *Function { |
202 | fn, _ := prog.packageLevelMember(obj).(*Function) |
203 | return fn |
204 | } |
205 | |
206 | // ConstValue returns the SSA Value denoted by the source-level named |
207 | // constant obj. |
208 | func (prog *Program) ConstValue(obj *types.Const) *Const { |
209 | // TODO(adonovan): opt: share (don't reallocate) |
210 | // Consts for const objects and constant ast.Exprs. |
211 | |
212 | // Universal constant? {true,false,nil} |
213 | if obj.Parent() == types.Universe { |
214 | return NewConst(obj.Val(), obj.Type()) |
215 | } |
216 | // Package-level named constant? |
217 | if v := prog.packageLevelMember(obj); v != nil { |
218 | return v.(*NamedConst).Value |
219 | } |
220 | return NewConst(obj.Val(), obj.Type()) |
221 | } |
222 | |
223 | // VarValue returns the SSA Value that corresponds to a specific |
224 | // identifier denoting the source-level named variable obj. |
225 | // |
226 | // VarValue returns nil if a local variable was not found, perhaps |
227 | // because its package was not built, the debug information was not |
228 | // requested during SSA construction, or the value was optimized away. |
229 | // |
230 | // ref is the path to an ast.Ident (e.g. from PathEnclosingInterval), |
231 | // and that ident must resolve to obj. |
232 | // |
233 | // pkg is the package enclosing the reference. (A reference to a var |
234 | // always occurs within a function, so we need to know where to find it.) |
235 | // |
236 | // If the identifier is a field selector and its base expression is |
237 | // non-addressable, then VarValue returns the value of that field. |
238 | // For example: |
239 | // |
240 | // func f() struct {x int} |
241 | // f().x // VarValue(x) returns a *Field instruction of type int |
242 | // |
243 | // All other identifiers denote addressable locations (variables). |
244 | // For them, VarValue may return either the variable's address or its |
245 | // value, even when the expression is evaluated only for its value; the |
246 | // situation is reported by isAddr, the second component of the result. |
247 | // |
248 | // If !isAddr, the returned value is the one associated with the |
249 | // specific identifier. For example, |
250 | // |
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 | func (prog *Program) VarValue(obj *types.Var, pkg *Package, ref []ast.Node) (value Value, isAddr bool) { |
259 | // All references to a var are local to some function, possibly init. |
260 | fn := EnclosingFunction(pkg, ref) |
261 | if fn == nil { |
262 | return // e.g. def of struct field; SSA not built? |
263 | } |
264 | |
265 | id := ref[0].(*ast.Ident) |
266 | |
267 | // Defining ident of a parameter? |
268 | if id.Pos() == obj.Pos() { |
269 | for _, param := range fn.Params { |
270 | if param.Object() == obj { |
271 | return param, false |
272 | } |
273 | } |
274 | } |
275 | |
276 | // Other ident? |
277 | for _, b := range fn.Blocks { |
278 | for _, instr := range b.Instrs { |
279 | if dr, ok := instr.(*DebugRef); ok { |
280 | if dr.Pos() == id.Pos() { |
281 | return dr.X, dr.IsAddr |
282 | } |
283 | } |
284 | } |
285 | } |
286 | |
287 | // Defining ident of package-level var? |
288 | if v := prog.packageLevelMember(obj); v != nil { |
289 | return v.(*Global), true |
290 | } |
291 | |
292 | return // e.g. debug info not requested, or var optimized away |
293 | } |
294 |
Members