github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/types/typeutil/callee.go (about) 1 // Copyright 2018 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 typeutil 6 7 import ( 8 "go/ast" 9 "go/types" 10 11 "golang.org/x/tools/go/ast/astutil" 12 "golang.org/x/tools/internal/typeparams" 13 ) 14 15 // Callee returns the named target of a function call, if any: 16 // a function, method, builtin, or variable. 17 // 18 // Functions and methods may potentially have type parameters. 19 func Callee(info *types.Info, call *ast.CallExpr) types.Object { 20 fun := astutil.Unparen(call.Fun) 21 22 // Look through type instantiation if necessary. 23 isInstance := false 24 switch fun.(type) { 25 case *ast.IndexExpr, *typeparams.IndexListExpr: 26 // When extracting the callee from an *IndexExpr, we need to check that 27 // it is a *types.Func and not a *types.Var. 28 // Example: Don't match a slice m within the expression `m[0]()`. 29 isInstance = true 30 fun, _, _, _ = typeparams.UnpackIndexExpr(fun) 31 } 32 33 var obj types.Object 34 switch fun := fun.(type) { 35 case *ast.Ident: 36 obj = info.Uses[fun] // type, var, builtin, or declared func 37 case *ast.SelectorExpr: 38 if sel, ok := info.Selections[fun]; ok { 39 obj = sel.Obj() // method or field 40 } else { 41 obj = info.Uses[fun.Sel] // qualified identifier? 42 } 43 } 44 if _, ok := obj.(*types.TypeName); ok { 45 return nil // T(x) is a conversion, not a call 46 } 47 // A Func is required to match instantiations. 48 if _, ok := obj.(*types.Func); isInstance && !ok { 49 return nil // Was not a Func. 50 } 51 return obj 52 } 53 54 // StaticCallee returns the target (function or method) of a static function 55 // call, if any. It returns nil for calls to builtins. 56 // 57 // Note: for calls of instantiated functions and methods, StaticCallee returns 58 // the corresponding generic function or method on the generic type. 59 func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func { 60 if f, ok := Callee(info, call).(*types.Func); ok && !interfaceMethod(f) { 61 return f 62 } 63 return nil 64 } 65 66 func interfaceMethod(f *types.Func) bool { 67 recv := f.Type().(*types.Signature).Recv() 68 return recv != nil && types.IsInterface(recv.Type()) 69 }