github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 Run: run, 30 RunDespiteErrors: true, 31 FactTypes: []analysis.Fact{new(foundFact)}, 32 } 33 34 var name string // -name flag 35 36 func init() { 37 Analyzer.Flags.StringVar(&name, "name", name, "name of the function to find") 38 } 39 40 func run(pass *analysis.Pass) (interface{}, error) { 41 for _, f := range pass.Files { 42 ast.Inspect(f, func(n ast.Node) bool { 43 if call, ok := n.(*ast.CallExpr); ok { 44 var id *ast.Ident 45 switch fun := call.Fun.(type) { 46 case *ast.Ident: 47 id = fun 48 case *ast.SelectorExpr: 49 id = fun.Sel 50 } 51 if id != nil && !pass.TypesInfo.Types[id].IsType() && id.Name == name { 52 pass.Report(analysis.Diagnostic{ 53 Pos: call.Lparen, 54 Message: fmt.Sprintf("call of %s(...)", id.Name), 55 SuggestedFixes: []analysis.SuggestedFix{{ 56 Message: fmt.Sprintf("Add '_TEST_'"), 57 TextEdits: []analysis.TextEdit{{ 58 Pos: call.Lparen, 59 End: call.Lparen, 60 NewText: []byte("_TEST_"), 61 }}, 62 }}, 63 }) 64 } 65 } 66 return true 67 }) 68 } 69 70 // Export a fact for each matching function. 71 // 72 // These facts are produced only to test the testing 73 // infrastructure in the analysistest package. 74 // They are not consumed by the findcall Analyzer 75 // itself, as would happen in a more realistic example. 76 for _, f := range pass.Files { 77 for _, decl := range f.Decls { 78 if decl, ok := decl.(*ast.FuncDecl); ok && decl.Name.Name == name { 79 if obj, ok := pass.TypesInfo.Defs[decl.Name].(*types.Func); ok { 80 pass.ExportObjectFact(obj, new(foundFact)) 81 } 82 } 83 } 84 } 85 86 if len(pass.AllObjectFacts()) > 0 { 87 pass.ExportPackageFact(new(foundFact)) 88 } 89 90 return nil, nil 91 } 92 93 // foundFact is a fact associated with functions that match -name. 94 // We use it to exercise the fact machinery in tests. 95 type foundFact struct{} 96 97 func (*foundFact) String() string { return "found" } 98 func (*foundFact) AFact() {}