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// The findcall package 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.
9package findcall
10
11import (
12	"go/ast"
13	"go/types"
14
15	"golang.org/x/tools/go/analysis"
16)
17
18const Doc = `find calls to a particular function
19
20The findcall analysis reports calls to functions or methods
21of a particular name.`
22
23var Analyzer = &analysis.Analyzer{
24	Name:             "findcall",
25	Doc:              Doc,
26	Run:              run,
27	RunDespiteErrors: true,
28	FactTypes:        []analysis.Fact{new(foundFact)},
29}
30
31var name string // -name flag
32
33func init() {
34	Analyzer.Flags.StringVar(&name, "name", name, "name of the function to find")
35}
36
37func run(pass *analysis.Pass) (interface{}, error) {
38	for _, f := range pass.Files {
39		ast.Inspect(f, func(n ast.Node) bool {
40			if call, ok := n.(*ast.CallExpr); ok {
41				var id *ast.Ident
42				switch fun := call.Fun.(type) {
43				case *ast.Ident:
44					id = fun
45				case *ast.SelectorExpr:
46					id = fun.Sel
47				}
48				if id != nil && !pass.TypesInfo.Types[id].IsType() && id.Name == name {
49					pass.Reportf(call.Lparen, "call of %s(...)", id.Name)
50				}
51			}
52			return true
53		})
54	}
55
56	// Export a fact for each matching function.
57	//
58	// These facts are produced only to test the testing
59	// infrastructure in the analysistest package.
60	// They are not consumed by the findcall Analyzer
61	// itself, as would happen in a more realistic example.
62	for _, f := range pass.Files {
63		for _, decl := range f.Decls {
64			if decl, ok := decl.(*ast.FuncDecl); ok && decl.Name.Name == name {
65				if obj, ok := pass.TypesInfo.Defs[decl.Name].(*types.Func); ok {
66					pass.ExportObjectFact(obj, new(foundFact))
67				}
68			}
69		}
70	}
71
72	return nil, nil
73}
74
75// foundFact is a fact associated with functions that match -name.
76// We use it to exercise the fact machinery in tests.
77type foundFact struct{}
78
79func (*foundFact) String() string { return "found" }
80func (*foundFact) AFact()         {}
81