...

Source file src/golang.org/x/tools/go/analysis/passes/findcall/findcall.go

Documentation: golang.org/x/tools/go/analysis/passes/findcall

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

View as plain text