golang.org/x/tools@v0.21.0/go/analysis/passes/findcall/findcall.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 findcall defines an Analyzer that serves as a trivial 6 // example and test of the Analysis API. It reports a diagnostic for 7 // every call to a function or method of the name specified by its 8 // -name flag. It also exports a fact for each declaration that 9 // matches the name, plus a package-level fact if the package contained 10 // one or more such declarations. 11 package findcall 12 13 import ( 14 "fmt" 15 "go/ast" 16 "go/types" 17 18 "golang.org/x/tools/go/analysis" 19 ) 20 21 const Doc = `find calls to a particular function 22 23 The findcall analysis reports calls to functions or methods 24 of a particular name.` 25 26 var Analyzer = &analysis.Analyzer{ 27 Name: "findcall", 28 Doc: Doc, 29 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/findcall", 30 Run: run, 31 RunDespiteErrors: true, 32 FactTypes: []analysis.Fact{new(foundFact)}, 33 } 34 35 var name string // -name flag 36 37 func init() { 38 Analyzer.Flags.StringVar(&name, "name", name, "name of the function to find") 39 } 40 41 func run(pass *analysis.Pass) (interface{}, error) { 42 for _, f := range pass.Files { 43 ast.Inspect(f, func(n ast.Node) bool { 44 if call, ok := n.(*ast.CallExpr); ok { 45 var id *ast.Ident 46 switch fun := call.Fun.(type) { 47 case *ast.Ident: 48 id = fun 49 case *ast.SelectorExpr: 50 id = fun.Sel 51 } 52 if id != nil && !pass.TypesInfo.Types[id].IsType() && id.Name == name { 53 pass.Report(analysis.Diagnostic{ 54 Pos: call.Lparen, 55 Message: fmt.Sprintf("call of %s(...)", id.Name), 56 SuggestedFixes: []analysis.SuggestedFix{{ 57 Message: fmt.Sprintf("Add '_TEST_'"), 58 TextEdits: []analysis.TextEdit{{ 59 Pos: call.Lparen, 60 End: call.Lparen, 61 NewText: []byte("_TEST_"), 62 }}, 63 }}, 64 }) 65 } 66 } 67 return true 68 }) 69 } 70 71 // Export a fact for each matching function. 72 // 73 // These facts are produced only to test the testing 74 // infrastructure in the analysistest package. 75 // They are not consumed by the findcall Analyzer 76 // itself, as would happen in a more realistic example. 77 for _, f := range pass.Files { 78 for _, decl := range f.Decls { 79 if decl, ok := decl.(*ast.FuncDecl); ok && decl.Name.Name == name { 80 if obj, ok := pass.TypesInfo.Defs[decl.Name].(*types.Func); ok { 81 pass.ExportObjectFact(obj, new(foundFact)) 82 } 83 } 84 } 85 } 86 87 if len(pass.AllObjectFacts()) > 0 { 88 pass.ExportPackageFact(new(foundFact)) 89 } 90 91 return nil, nil 92 } 93 94 // foundFact is a fact associated with functions that match -name. 95 // We use it to exercise the fact machinery in tests. 96 type foundFact struct{} 97 98 func (*foundFact) String() string { return "found" } 99 func (*foundFact) AFact() {}