...
Source file src/pkg/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
1
2
3
4
5
6
7 package unusedresult
8
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
13 "sort"
14 "strings"
15
16 "golang.org/x/tools/go/analysis"
17 "golang.org/x/tools/go/analysis/passes/inspect"
18 "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
19 "golang.org/x/tools/go/ast/inspector"
20 )
21
22
23
24
25
26 const Doc = `check for unused results of calls to some functions
27
28 Some functions like fmt.Errorf return a result and have no side effects,
29 so it is always a mistake to discard the result. This analyzer reports
30 calls to certain functions in which the result of the call is ignored.
31
32 The set of functions may be controlled using flags.`
33
34 var Analyzer = &analysis.Analyzer{
35 Name: "unusedresult",
36 Doc: Doc,
37 Requires: []*analysis.Analyzer{inspect.Analyzer},
38 Run: run,
39 }
40
41
42 var funcs, stringMethods stringSetFlag
43
44 func init() {
45
46
47 funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse")
48 Analyzer.Flags.Var(&funcs, "funcs",
49 "comma-separated list of functions whose results must be used")
50
51 stringMethods.Set("Error,String")
52 Analyzer.Flags.Var(&stringMethods, "stringmethods",
53 "comma-separated list of names of methods of type func() string whose results must be used")
54 }
55
56 func run(pass *analysis.Pass) (interface{}, error) {
57 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
58
59 nodeFilter := []ast.Node{
60 (*ast.ExprStmt)(nil),
61 }
62 inspect.Preorder(nodeFilter, func(n ast.Node) {
63 call, ok := analysisutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
64 if !ok {
65 return
66 }
67 fun := analysisutil.Unparen(call.Fun)
68
69 if pass.TypesInfo.Types[fun].IsType() {
70 return
71 }
72
73 selector, ok := fun.(*ast.SelectorExpr)
74 if !ok {
75 return
76 }
77
78 sel, ok := pass.TypesInfo.Selections[selector]
79 if ok && sel.Kind() == types.MethodVal {
80
81 obj := sel.Obj().(*types.Func)
82 sig := sel.Type().(*types.Signature)
83 if types.Identical(sig, sigNoArgsStringResult) {
84 if stringMethods[obj.Name()] {
85 pass.Reportf(call.Lparen, "result of (%s).%s call not used",
86 sig.Recv().Type(), obj.Name())
87 }
88 }
89 } else if !ok {
90
91 obj := pass.TypesInfo.Uses[selector.Sel]
92 if obj, ok := obj.(*types.Func); ok {
93 qname := obj.Pkg().Path() + "." + obj.Name()
94 if funcs[qname] {
95 pass.Reportf(call.Lparen, "result of %v call not used", qname)
96 }
97 }
98 }
99 })
100 return nil, nil
101 }
102
103
104 var sigNoArgsStringResult = types.NewSignature(nil, nil,
105 types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])),
106 false)
107
108 type stringSetFlag map[string]bool
109
110 func (ss *stringSetFlag) String() string {
111 var items []string
112 for item := range *ss {
113 items = append(items, item)
114 }
115 sort.Strings(items)
116 return strings.Join(items, ",")
117 }
118
119 func (ss *stringSetFlag) Set(s string) error {
120 m := make(map[string]bool)
121 if s != "" {
122 for _, name := range strings.Split(s, ",") {
123 if name == "" {
124 continue
125 }
126 m[name] = true
127 }
128 }
129 *ss = m
130 return nil
131 }
132
View as plain text