--- /dev/null
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package findcall defines an Analyzer that serves as a trivial
+// example and test of the Analysis API. It reports a diagnostic for
+// every call to a function or method of the name specified by its
+// -name flag. It also exports a fact for each declaration that
+// matches the name, plus a package-level fact if the package contained
+// one or more such declarations.
+package findcall
+
+import (
+ "fmt"
+ "go/ast"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+const Doc = `find calls to a particular function
+
+The findcall analysis reports calls to functions or methods
+of a particular name.`
+
+var Analyzer = &analysis.Analyzer{
+ Name: "findcall",
+ Doc: Doc,
+ Run: run,
+ RunDespiteErrors: true,
+ FactTypes: []analysis.Fact{new(foundFact)},
+}
+
+var name string // -name flag
+
+func init() {
+ Analyzer.Flags.StringVar(&name, "name", name, "name of the function to find")
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ for _, f := range pass.Files {
+ ast.Inspect(f, func(n ast.Node) bool {
+ if call, ok := n.(*ast.CallExpr); ok {
+ var id *ast.Ident
+ switch fun := call.Fun.(type) {
+ case *ast.Ident:
+ id = fun
+ case *ast.SelectorExpr:
+ id = fun.Sel
+ }
+ if id != nil && !pass.TypesInfo.Types[id].IsType() && id.Name == name {
+ pass.Report(analysis.Diagnostic{
+ Pos: call.Lparen,
+ Message: fmt.Sprintf("call of %s(...)", id.Name),
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: fmt.Sprintf("Add '_TEST_'"),
+ TextEdits: []analysis.TextEdit{{
+ Pos: call.Lparen,
+ End: call.Lparen,
+ NewText: []byte("_TEST_"),
+ }},
+ }},
+ })
+ }
+ }
+ return true
+ })
+ }
+
+ // Export a fact for each matching function.
+ //
+ // These facts are produced only to test the testing
+ // infrastructure in the analysistest package.
+ // They are not consumed by the findcall Analyzer
+ // itself, as would happen in a more realistic example.
+ for _, f := range pass.Files {
+ for _, decl := range f.Decls {
+ if decl, ok := decl.(*ast.FuncDecl); ok && decl.Name.Name == name {
+ if obj, ok := pass.TypesInfo.Defs[decl.Name].(*types.Func); ok {
+ pass.ExportObjectFact(obj, new(foundFact))
+ }
+ }
+ }
+ }
+
+ if len(pass.AllObjectFacts()) > 0 {
+ pass.ExportPackageFact(new(foundFact))
+ }
+
+ return nil, nil
+}
+
+// foundFact is a fact associated with functions that match -name.
+// We use it to exercise the fact machinery in tests.
+type foundFact struct{}
+
+func (*foundFact) String() string { return "found" }
+func (*foundFact) AFact() {}