You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
9.2 KiB

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