golang.org/x/tools@v0.21.0/go/analysis/passes/testinggoroutine/util.go (about) 1 // Copyright 2023 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 testinggoroutine 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 // AST and types utilities that not specific to testinggoroutines. 16 17 // localFunctionDecls returns a mapping from *types.Func to *ast.FuncDecl in files. 18 func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) *ast.FuncDecl { 19 var fnDecls map[*types.Func]*ast.FuncDecl // computed lazily 20 return func(f *types.Func) *ast.FuncDecl { 21 if f != nil && fnDecls == nil { 22 fnDecls = make(map[*types.Func]*ast.FuncDecl) 23 for _, file := range files { 24 for _, decl := range file.Decls { 25 if fnDecl, ok := decl.(*ast.FuncDecl); ok { 26 if fn, ok := info.Defs[fnDecl.Name].(*types.Func); ok { 27 fnDecls[fn] = fnDecl 28 } 29 } 30 } 31 } 32 } 33 // TODO: set f = f.Origin() here. 34 return fnDecls[f] 35 } 36 } 37 38 // isMethodNamed returns true if f is a method defined 39 // in package with the path pkgPath with a name in names. 40 func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool { 41 if f == nil { 42 return false 43 } 44 if f.Pkg() == nil || f.Pkg().Path() != pkgPath { 45 return false 46 } 47 if f.Type().(*types.Signature).Recv() == nil { 48 return false 49 } 50 for _, n := range names { 51 if f.Name() == n { 52 return true 53 } 54 } 55 return false 56 } 57 58 func funcIdent(fun ast.Expr) *ast.Ident { 59 switch fun := astutil.Unparen(fun).(type) { 60 case *ast.IndexExpr, *ast.IndexListExpr: 61 x, _, _, _ := typeparams.UnpackIndexExpr(fun) // necessary? 62 id, _ := x.(*ast.Ident) 63 return id 64 case *ast.Ident: 65 return fun 66 default: 67 return nil 68 } 69 } 70 71 // funcLitInScope returns a FuncLit that id is at least initially assigned to. 72 // 73 // TODO: This is closely tied to id.Obj which is deprecated. 74 func funcLitInScope(id *ast.Ident) *ast.FuncLit { 75 // Compare to (*ast.Object).Pos(). 76 if id.Obj == nil { 77 return nil 78 } 79 var rhs ast.Expr 80 switch d := id.Obj.Decl.(type) { 81 case *ast.AssignStmt: 82 for i, x := range d.Lhs { 83 if ident, isIdent := x.(*ast.Ident); isIdent && ident.Name == id.Name && i < len(d.Rhs) { 84 rhs = d.Rhs[i] 85 } 86 } 87 case *ast.ValueSpec: 88 for i, n := range d.Names { 89 if n.Name == id.Name && i < len(d.Values) { 90 rhs = d.Values[i] 91 } 92 } 93 } 94 lit, _ := rhs.(*ast.FuncLit) 95 return lit 96 }