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.
7 // This file defines utilities for working with source positions
8 // or source-level named entities ("objects").
10 // TODO(adonovan): test that {Value,Instruction}.Pos() positions match
11 // the originating syntax, as specified.
19 // EnclosingFunction returns the function that contains the syntax
20 // node denoted by path.
22 // Syntax associated with package-level variable specifications is
23 // enclosed by the package's init() function.
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).
31 func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
32 // Start with package-level function...
33 fn := findEnclosingPackageLevelFunction(pkg, path)
35 return nil // not in any function
38 // ...then walk down the nested anonymous functions.
42 if lit, ok := path[n-1-i].(*ast.FuncLit); ok {
43 for _, anon := range fn.AnonFuncs {
44 if anon.Pos() == lit.Type.Func {
49 // SSA function not found:
50 // - package not yet built, or maybe
51 // - builder skipped FuncLit in dead block
52 // (in principle; but currently the Builder
53 // generates even dead FuncLits).
60 // HasEnclosingFunction returns true if the AST node denoted by path
61 // is contained within the declaration of some function or
62 // package-level variable.
64 // Unlike EnclosingFunction, the behaviour of this function does not
65 // depend on whether SSA code for pkg has been built, so it can be
66 // used to quickly reject check inputs that will cause
67 // EnclosingFunction to fail, prior to SSA building.
69 func HasEnclosingFunction(pkg *Package, path []ast.Node) bool {
70 return findEnclosingPackageLevelFunction(pkg, path) != nil
73 // findEnclosingPackageLevelFunction returns the Function
74 // corresponding to the package-level function enclosing path.
76 func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function {
77 if n := len(path); n >= 2 { // [... {Gen,Func}Decl File]
78 switch decl := path[n-2].(type) {
80 if decl.Tok == token.VAR && n >= 3 {
81 // Package-level 'var' initializer.
86 if decl.Recv == nil && decl.Name.Name == "init" {
87 // Explicit init() function.
88 for _, b := range pkg.init.Blocks {
89 for _, instr := range b.Instrs {
90 if instr, ok := instr.(*Call); ok {
91 if callee, ok := instr.Call.Value.(*Function); ok && callee.Pkg == pkg && callee.Pos() == decl.Name.NamePos {
97 // Hack: return non-nil when SSA is not yet
98 // built so that HasEnclosingFunction works.
101 // Declared function/method.
102 return findNamedFunc(pkg, decl.Name.NamePos)
105 return nil // not in any function
108 // findNamedFunc returns the named function whose FuncDecl.Ident is at
111 func findNamedFunc(pkg *Package, pos token.Pos) *Function {
112 // Look at all package members and method sets of named types.
113 // Not very efficient.
114 for _, mem := range pkg.Members {
115 switch mem := mem.(type) {
117 if mem.Pos() == pos {
121 mset := pkg.Prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
122 for i, n := 0, mset.Len(); i < n; i++ {
123 // Don't call Program.Method: avoid creating wrappers.
124 obj := mset.At(i).Obj().(*types.Func)
125 if obj.Pos() == pos {
126 return pkg.values[obj].(*Function)
134 // ValueForExpr returns the SSA Value that corresponds to non-constant
137 // It returns nil if no value was found, e.g.
138 // - the expression is not lexically contained within f;
139 // - f was not built with debug information; or
140 // - e is a constant expression. (For efficiency, no debug
141 // information is stored for constants. Use
142 // go/types.Info.Types[e].Value instead.)
143 // - e is a reference to nil or a built-in function.
144 // - the value was optimised away.
146 // If e is an addressable expression used in an lvalue context,
147 // value is the address denoted by e, and isAddr is true.
149 // The types of e (or &e, if isAddr) and the result are equal
150 // (modulo "untyped" bools resulting from comparisons).
152 // (Tip: to find the ssa.Value given a source position, use
153 // astutil.PathEnclosingInterval to locate the ast.Node, then
154 // EnclosingFunction to locate the Function, then ValueForExpr to find
157 func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) {
158 if f.debugInfo() { // (opt)
160 for _, b := range f.Blocks {
161 for _, instr := range b.Instrs {
162 if ref, ok := instr.(*DebugRef); ok {
164 return ref.X, ref.IsAddr
173 // --- Lookup functions for source-level named entities (types.Objects) ---
175 // Package returns the SSA Package corresponding to the specified
176 // type-checker package object.
177 // It returns nil if no such SSA package has been created.
179 func (prog *Program) Package(obj *types.Package) *Package {
180 return prog.packages[obj]
183 // packageLevelValue returns the package-level value corresponding to
184 // the specified named object, which may be a package-level const
185 // (*Const), var (*Global) or func (*Function) of some package in
186 // prog. It returns nil if the object is not found.
188 func (prog *Program) packageLevelValue(obj types.Object) Value {
189 if pkg, ok := prog.packages[obj.Pkg()]; ok {
190 return pkg.values[obj]
195 // FuncValue returns the concrete Function denoted by the source-level
196 // named function obj, or nil if obj denotes an interface method.
198 // TODO(adonovan): check the invariant that obj.Type() matches the
199 // result's Signature, both in the params/results and in the receiver.
201 func (prog *Program) FuncValue(obj *types.Func) *Function {
202 fn, _ := prog.packageLevelValue(obj).(*Function)
206 // ConstValue returns the SSA Value denoted by the source-level named
209 func (prog *Program) ConstValue(obj *types.Const) *Const {
210 // TODO(adonovan): opt: share (don't reallocate)
211 // Consts for const objects and constant ast.Exprs.
213 // Universal constant? {true,false,nil}
214 if obj.Parent() == types.Universe {
215 return NewConst(obj.Val(), obj.Type())
217 // Package-level named constant?
218 if v := prog.packageLevelValue(obj); v != nil {
221 return NewConst(obj.Val(), obj.Type())
224 // VarValue returns the SSA Value that corresponds to a specific
225 // identifier denoting the source-level named variable obj.
227 // VarValue returns nil if a local variable was not found, perhaps
228 // because its package was not built, the debug information was not
229 // requested during SSA construction, or the value was optimized away.
231 // ref is the path to an ast.Ident (e.g. from PathEnclosingInterval),
232 // and that ident must resolve to obj.
234 // pkg is the package enclosing the reference. (A reference to a var
235 // always occurs within a function, so we need to know where to find it.)
237 // If the identifier is a field selector and its base expression is
238 // non-addressable, then VarValue returns the value of that field.
240 // func f() struct {x int}
241 // f().x // VarValue(x) returns a *Field instruction of type int
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.
248 // If !isAddr, the returned value is the one associated with the
249 // specific identifier. For example,
250 // var x int // VarValue(x) returns Const 0 here
251 // x = 1 // VarValue(x) returns Const 1 here
253 // It is not specified whether the value or the address is returned in
254 // any particular case, as it may depend upon optimizations performed
255 // during SSA code generation, such as registerization, constant
256 // 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)
262 return // e.g. def of struct field; SSA not built?
265 id := ref[0].(*ast.Ident)
267 // Defining ident of a parameter?
268 if id.Pos() == obj.Pos() {
269 for _, param := range fn.Params {
270 if param.Object() == obj {
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
287 // Defining ident of package-level var?
288 if v := prog.packageLevelValue(obj); v != nil {
289 return v.(*Global), true
292 return // e.g. debug info not requested, or var optimized away