Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / ir / source.go
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 ir
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 IR function has not been created yet
29 //      (pkg.Build() has not yet been called).
30 //
31 func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
32         // Start with package-level function...
33         fn := findEnclosingPackageLevelFunction(pkg, path)
34         if fn == nil {
35                 return nil // not in any function
36         }
37
38         // ...then walk down the nested anonymous functions.
39         n := len(path)
40 outer:
41         for i := range path {
42                 if lit, ok := path[n-1-i].(*ast.FuncLit); ok {
43                         for _, anon := range fn.AnonFuncs {
44                                 if anon.Pos() == lit.Type.Func {
45                                         fn = anon
46                                         continue outer
47                                 }
48                         }
49                         // IR 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).
54                         return nil
55                 }
56         }
57         return fn
58 }
59
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.
63 //
64 // Unlike EnclosingFunction, the behaviour of this function does not
65 // depend on whether IR 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 IR building.
68 //
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 //
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) {
79                 case *ast.GenDecl:
80                         if decl.Tok == token.VAR && n >= 3 {
81                                 // Package-level 'var' initializer.
82                                 return pkg.init
83                         }
84
85                 case *ast.FuncDecl:
86                         // Declared function/method.
87                         fn := findNamedFunc(pkg, decl.Pos())
88                         if fn == nil && decl.Recv == nil && decl.Name.Name == "init" {
89                                 // Hack: return non-nil when IR is not yet
90                                 // built so that HasEnclosingFunction works.
91                                 return pkg.init
92                         }
93                         return fn
94                 }
95         }
96         return nil // not in any function
97 }
98
99 // findNamedFunc returns the named function whose FuncDecl.Ident is at
100 // position pos.
101 //
102 func findNamedFunc(pkg *Package, pos token.Pos) *Function {
103         for _, fn := range pkg.Functions {
104                 if fn.Pos() == pos {
105                         return fn
106                 }
107         }
108         return nil
109 }
110
111 // ValueForExpr returns the IR Value that corresponds to non-constant
112 // expression e.
113 //
114 // It returns nil if no value was found, e.g.
115 //    - the expression is not lexically contained within f;
116 //    - f was not built with debug information; or
117 //    - e is a constant expression.  (For efficiency, no debug
118 //      information is stored for constants. Use
119 //      go/types.Info.Types[e].Value instead.)
120 //    - e is a reference to nil or a built-in function.
121 //    - the value was optimised away.
122 //
123 // If e is an addressable expression used in an lvalue context,
124 // value is the address denoted by e, and isAddr is true.
125 //
126 // The types of e (or &e, if isAddr) and the result are equal
127 // (modulo "untyped" bools resulting from comparisons).
128 //
129 // (Tip: to find the ir.Value given a source position, use
130 // astutil.PathEnclosingInterval to locate the ast.Node, then
131 // EnclosingFunction to locate the Function, then ValueForExpr to find
132 // the ir.Value.)
133 //
134 func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) {
135         if f.debugInfo() { // (opt)
136                 e = unparen(e)
137                 for _, b := range f.Blocks {
138                         for _, instr := range b.Instrs {
139                                 if ref, ok := instr.(*DebugRef); ok {
140                                         if ref.Expr == e {
141                                                 return ref.X, ref.IsAddr
142                                         }
143                                 }
144                         }
145                 }
146         }
147         return
148 }
149
150 // --- Lookup functions for source-level named entities (types.Objects) ---
151
152 // Package returns the IR Package corresponding to the specified
153 // type-checker package object.
154 // It returns nil if no such IR package has been created.
155 //
156 func (prog *Program) Package(obj *types.Package) *Package {
157         return prog.packages[obj]
158 }
159
160 // packageLevelValue returns the package-level value corresponding to
161 // the specified named object, which may be a package-level const
162 // (*Const), var (*Global) or func (*Function) of some package in
163 // prog.  It returns nil if the object is not found.
164 //
165 func (prog *Program) packageLevelValue(obj types.Object) Value {
166         if pkg, ok := prog.packages[obj.Pkg()]; ok {
167                 return pkg.values[obj]
168         }
169         return nil
170 }
171
172 // FuncValue returns the concrete Function denoted by the source-level
173 // named function obj, or nil if obj denotes an interface method.
174 //
175 // TODO(adonovan): check the invariant that obj.Type() matches the
176 // result's Signature, both in the params/results and in the receiver.
177 //
178 func (prog *Program) FuncValue(obj *types.Func) *Function {
179         fn, _ := prog.packageLevelValue(obj).(*Function)
180         return fn
181 }
182
183 // ConstValue returns the IR Value denoted by the source-level named
184 // constant obj.
185 //
186 func (prog *Program) ConstValue(obj *types.Const) *Const {
187         // TODO(adonovan): opt: share (don't reallocate)
188         // Consts for const objects and constant ast.Exprs.
189
190         // Universal constant? {true,false,nil}
191         if obj.Parent() == types.Universe {
192                 return NewConst(obj.Val(), obj.Type())
193         }
194         // Package-level named constant?
195         if v := prog.packageLevelValue(obj); v != nil {
196                 return v.(*Const)
197         }
198         return NewConst(obj.Val(), obj.Type())
199 }
200
201 // VarValue returns the IR Value that corresponds to a specific
202 // identifier denoting the source-level named variable obj.
203 //
204 // VarValue returns nil if a local variable was not found, perhaps
205 // because its package was not built, the debug information was not
206 // requested during IR construction, or the value was optimized away.
207 //
208 // ref is the path to an ast.Ident (e.g. from PathEnclosingInterval),
209 // and that ident must resolve to obj.
210 //
211 // pkg is the package enclosing the reference.  (A reference to a var
212 // always occurs within a function, so we need to know where to find it.)
213 //
214 // If the identifier is a field selector and its base expression is
215 // non-addressable, then VarValue returns the value of that field.
216 // For example:
217 //    func f() struct {x int}
218 //    f().x  // VarValue(x) returns a *Field instruction of type int
219 //
220 // All other identifiers denote addressable locations (variables).
221 // For them, VarValue may return either the variable's address or its
222 // value, even when the expression is evaluated only for its value; the
223 // situation is reported by isAddr, the second component of the result.
224 //
225 // If !isAddr, the returned value is the one associated with the
226 // specific identifier.  For example,
227 //       var x int    // VarValue(x) returns Const 0 here
228 //       x = 1        // VarValue(x) returns Const 1 here
229 //
230 // It is not specified whether the value or the address is returned in
231 // any particular case, as it may depend upon optimizations performed
232 // during IR code generation, such as registerization, constant
233 // folding, avoidance of materialization of subexpressions, etc.
234 //
235 func (prog *Program) VarValue(obj *types.Var, pkg *Package, ref []ast.Node) (value Value, isAddr bool) {
236         // All references to a var are local to some function, possibly init.
237         fn := EnclosingFunction(pkg, ref)
238         if fn == nil {
239                 return // e.g. def of struct field; IR not built?
240         }
241
242         id := ref[0].(*ast.Ident)
243
244         // Defining ident of a parameter?
245         if id.Pos() == obj.Pos() {
246                 for _, param := range fn.Params {
247                         if param.Object() == obj {
248                                 return param, false
249                         }
250                 }
251         }
252
253         // Other ident?
254         for _, b := range fn.Blocks {
255                 for _, instr := range b.Instrs {
256                         if dr, ok := instr.(*DebugRef); ok {
257                                 if dr.Pos() == id.Pos() {
258                                         return dr.X, dr.IsAddr
259                                 }
260                         }
261                 }
262         }
263
264         // Defining ident of package-level var?
265         if v := prog.packageLevelValue(obj); v != nil {
266                 return v.(*Global), true
267         }
268
269         return // e.g. debug info not requested, or var optimized away
270 }