github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/plugin/checker/internal/asthelpers/helpers.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package asthelpers 5 6 import ( 7 "go/ast" 8 "go/types" 9 10 "github.com/pkg/errors" 11 "golang.org/x/tools/go/packages" 12 ) 13 14 func GetPackage(pkgPath string) (*packages.Package, error) { 15 cfg := &packages.Config{ 16 Mode: packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo, 17 } 18 pkgs, err := packages.Load(cfg, pkgPath) 19 if err != nil { 20 return nil, err 21 } 22 23 if len(pkgs) == 0 { 24 return nil, errors.Errorf("could not find package %s", pkgPath) 25 } 26 return pkgs[0], nil 27 } 28 29 func FindInterface(name string, files []*ast.File) (*ast.InterfaceType, error) { 30 iface, _, err := FindInterfaceWithIdent(name, files) 31 return iface, err 32 } 33 34 func FindInterfaceWithIdent(name string, files []*ast.File) (*ast.InterfaceType, *ast.Ident, error) { 35 var ( 36 ident *ast.Ident 37 iface *ast.InterfaceType 38 ) 39 40 for _, f := range files { 41 ast.Inspect(f, func(n ast.Node) bool { 42 if t, ok := n.(*ast.TypeSpec); ok { 43 if iface != nil { 44 return false 45 } 46 47 if i, ok := t.Type.(*ast.InterfaceType); ok && t.Name.Name == name { 48 ident = t.Name 49 iface = i 50 return false 51 } 52 } 53 return true 54 }) 55 56 if iface != nil { 57 return iface, ident, nil 58 } 59 } 60 return nil, nil, errors.Errorf("could not find %s interface", name) 61 } 62 63 func FindMethodsCalledOnType(info *types.Info, typ types.Type, caller *ast.FuncDecl) []string { 64 var methods []string 65 66 ast.Inspect(caller, func(n ast.Node) bool { 67 if s, ok := n.(*ast.SelectorExpr); ok { 68 69 var receiver *ast.Ident 70 switch r := s.X.(type) { 71 case *ast.Ident: 72 // Left-hand side of the selector is an identifier, eg: 73 // 74 // a := p.API 75 // a.GetTeams() 76 // 77 receiver = r 78 case *ast.SelectorExpr: 79 // Left-hand side of the selector is a selector, eg: 80 // 81 // p.API.GetTeams() 82 // 83 receiver = r.Sel 84 } 85 86 if receiver != nil { 87 obj := info.ObjectOf(receiver) 88 if obj != nil && types.Identical(obj.Type(), typ) { 89 methods = append(methods, s.Sel.Name) 90 } 91 return false 92 } 93 94 } 95 return true 96 }) 97 98 return methods 99 } 100 101 func FindReceiverMethods(receiverName string, files []*ast.File) []*ast.FuncDecl { 102 var fns []*ast.FuncDecl 103 for _, f := range files { 104 ast.Inspect(f, func(n ast.Node) bool { 105 if fn, ok := n.(*ast.FuncDecl); ok { 106 r := extractReceiverTypeName(fn) 107 if r == receiverName { 108 fns = append(fns, fn) 109 } 110 } 111 return true 112 }) 113 } 114 return fns 115 } 116 117 func extractReceiverTypeName(fn *ast.FuncDecl) string { 118 if fn.Recv != nil { 119 t := fn.Recv.List[0].Type 120 // Unwrap the pointer type (a star expression) 121 if se, ok := t.(*ast.StarExpr); ok { 122 t = se.X 123 } 124 if id, ok := t.(*ast.Ident); ok { 125 return id.Name 126 } 127 } 128 return "" 129 }