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()         {}