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
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/ir/source.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/ir/source.go
new file mode 100644 (file)
index 0000000..93d1ccb
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ir
+
+// This file defines utilities for working with source positions
+// or source-level named entities ("objects").
+
+// TODO(adonovan): test that {Value,Instruction}.Pos() positions match
+// the originating syntax, as specified.
+
+import (
+       "go/ast"
+       "go/token"
+       "go/types"
+)
+
+// EnclosingFunction returns the function that contains the syntax
+// node denoted by path.
+//
+// Syntax associated with package-level variable specifications is
+// enclosed by the package's init() function.
+//
+// Returns nil if not found; reasons might include:
+//    - the node is not enclosed by any function.
+//    - the node is within an anonymous function (FuncLit) and
+//      its IR function has not been created yet
+//      (pkg.Build() has not yet been called).
+//
+func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
+       // Start with package-level function...
+       fn := findEnclosingPackageLevelFunction(pkg, path)
+       if fn == nil {
+               return nil // not in any function
+       }
+
+       // ...then walk down the nested anonymous functions.
+       n := len(path)
+outer:
+       for i := range path {
+               if lit, ok := path[n-1-i].(*ast.FuncLit); ok {
+                       for _, anon := range fn.AnonFuncs {
+                               if anon.Pos() == lit.Type.Func {
+                                       fn = anon
+                                       continue outer
+                               }
+                       }
+                       // IR function not found:
+                       // - package not yet built, or maybe
+                       // - builder skipped FuncLit in dead block
+                       //   (in principle; but currently the Builder
+                       //   generates even dead FuncLits).
+                       return nil
+               }
+       }
+       return fn
+}
+
+// HasEnclosingFunction returns true if the AST node denoted by path
+// is contained within the declaration of some function or
+// package-level variable.
+//
+// Unlike EnclosingFunction, the behaviour of this function does not
+// depend on whether IR code for pkg has been built, so it can be
+// used to quickly reject check inputs that will cause
+// EnclosingFunction to fail, prior to IR building.
+//
+func HasEnclosingFunction(pkg *Package, path []ast.Node) bool {
+       return findEnclosingPackageLevelFunction(pkg, path) != nil
+}
+
+// findEnclosingPackageLevelFunction returns the Function
+// corresponding to the package-level function enclosing path.
+//
+func findEnclosingPackageLevelFunction(pkg *Package, path []ast.Node) *Function {
+       if n := len(path); n >= 2 { // [... {Gen,Func}Decl File]
+               switch decl := path[n-2].(type) {
+               case *ast.GenDecl:
+                       if decl.Tok == token.VAR && n >= 3 {
+                               // Package-level 'var' initializer.
+                               return pkg.init
+                       }
+
+               case *ast.FuncDecl:
+                       // Declared function/method.
+                       fn := findNamedFunc(pkg, decl.Pos())
+                       if fn == nil && decl.Recv == nil && decl.Name.Name == "init" {
+                               // Hack: return non-nil when IR is not yet
+                               // built so that HasEnclosingFunction works.
+                               return pkg.init
+                       }
+                       return fn
+               }
+       }
+       return nil // not in any function
+}
+
+// findNamedFunc returns the named function whose FuncDecl.Ident is at
+// position pos.
+//
+func findNamedFunc(pkg *Package, pos token.Pos) *Function {
+       for _, fn := range pkg.Functions {
+               if fn.Pos() == pos {
+                       return fn
+               }
+       }
+       return nil
+}
+
+// ValueForExpr returns the IR Value that corresponds to non-constant
+// expression e.
+//
+// It returns nil if no value was found, e.g.
+//    - the expression is not lexically contained within f;
+//    - f was not built with debug information; or
+//    - e is a constant expression.  (For efficiency, no debug
+//      information is stored for constants. Use
+//      go/types.Info.Types[e].Value instead.)
+//    - e is a reference to nil or a built-in function.
+//    - the value was optimised away.
+//
+// If e is an addressable expression used in an lvalue context,
+// value is the address denoted by e, and isAddr is true.
+//
+// The types of e (or &e, if isAddr) and the result are equal
+// (modulo "untyped" bools resulting from comparisons).
+//
+// (Tip: to find the ir.Value given a source position, use
+// astutil.PathEnclosingInterval to locate the ast.Node, then
+// EnclosingFunction to locate the Function, then ValueForExpr to find
+// the ir.Value.)
+//
+func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) {
+       if f.debugInfo() { // (opt)
+               e = unparen(e)
+               for _, b := range f.Blocks {
+                       for _, instr := range b.Instrs {
+                               if ref, ok := instr.(*DebugRef); ok {
+                                       if ref.Expr == e {
+                                               return ref.X, ref.IsAddr
+                                       }
+                               }
+                       }
+               }
+       }
+       return
+}
+
+// --- Lookup functions for source-level named entities (types.Objects) ---
+
+// Package returns the IR Package corresponding to the specified
+// type-checker package object.
+// It returns nil if no such IR package has been created.
+//
+func (prog *Program) Package(obj *types.Package) *Package {
+       return prog.packages[obj]
+}
+
+// packageLevelValue returns the package-level value corresponding to
+// the specified named object, which may be a package-level const
+// (*Const), var (*Global) or func (*Function) of some package in
+// prog.  It returns nil if the object is not found.
+//
+func (prog *Program) packageLevelValue(obj types.Object) Value {
+       if pkg, ok := prog.packages[obj.Pkg()]; ok {
+               return pkg.values[obj]
+       }
+       return nil
+}
+
+// FuncValue returns the concrete Function denoted by the source-level
+// named function obj, or nil if obj denotes an interface method.
+//
+// TODO(adonovan): check the invariant that obj.Type() matches the
+// result's Signature, both in the params/results and in the receiver.
+//
+func (prog *Program) FuncValue(obj *types.Func) *Function {
+       fn, _ := prog.packageLevelValue(obj).(*Function)
+       return fn
+}
+
+// ConstValue returns the IR Value denoted by the source-level named
+// constant obj.
+//
+func (prog *Program) ConstValue(obj *types.Const) *Const {
+       // TODO(adonovan): opt: share (don't reallocate)
+       // Consts for const objects and constant ast.Exprs.
+
+       // Universal constant? {true,false,nil}
+       if obj.Parent() == types.Universe {
+               return NewConst(obj.Val(), obj.Type())
+       }
+       // Package-level named constant?
+       if v := prog.packageLevelValue(obj); v != nil {
+               return v.(*Const)
+       }
+       return NewConst(obj.Val(), obj.Type())
+}
+
+// VarValue returns the IR Value that corresponds to a specific
+// identifier denoting the source-level named variable obj.
+//
+// VarValue returns nil if a local variable was not found, perhaps
+// because its package was not built, the debug information was not
+// requested during IR construction, or the value was optimized away.
+//
+// ref is the path to an ast.Ident (e.g. from PathEnclosingInterval),
+// and that ident must resolve to obj.
+//
+// pkg is the package enclosing the reference.  (A reference to a var
+// always occurs within a function, so we need to know where to find it.)
+//
+// If the identifier is a field selector and its base expression is
+// non-addressable, then VarValue returns the value of that field.
+// For example:
+//    func f() struct {x int}
+//    f().x  // VarValue(x) returns a *Field instruction of type int
+//
+// All other identifiers denote addressable locations (variables).
+// For them, VarValue may return either the variable's address or its
+// value, even when the expression is evaluated only for its value; the
+// situation is reported by isAddr, the second component of the result.
+//
+// If !isAddr, the returned value is the one associated with the
+// specific identifier.  For example,
+//       var x int    // VarValue(x) returns Const 0 here
+//       x = 1        // VarValue(x) returns Const 1 here
+//
+// It is not specified whether the value or the address is returned in
+// any particular case, as it may depend upon optimizations performed
+// during IR code generation, such as registerization, constant
+// folding, avoidance of materialization of subexpressions, etc.
+//
+func (prog *Program) VarValue(obj *types.Var, pkg *Package, ref []ast.Node) (value Value, isAddr bool) {
+       // All references to a var are local to some function, possibly init.
+       fn := EnclosingFunction(pkg, ref)
+       if fn == nil {
+               return // e.g. def of struct field; IR not built?
+       }
+
+       id := ref[0].(*ast.Ident)
+
+       // Defining ident of a parameter?
+       if id.Pos() == obj.Pos() {
+               for _, param := range fn.Params {
+                       if param.Object() == obj {
+                               return param, false
+                       }
+               }
+       }
+
+       // Other ident?
+       for _, b := range fn.Blocks {
+               for _, instr := range b.Instrs {
+                       if dr, ok := instr.(*DebugRef); ok {
+                               if dr.Pos() == id.Pos() {
+                                       return dr.X, dr.IsAddr
+                               }
+                       }
+               }
+       }
+
+       // Defining ident of package-level var?
+       if v := prog.packageLevelValue(obj); v != nil {
+               return v.(*Global), true
+       }
+
+       return // e.g. debug info not requested, or var optimized away
+}