Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / analysis / passes / unusedresult / unusedresult.go
1 // Copyright 2015 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 unusedresult defines an analyzer that checks for unused
6 // results of calls to certain pure functions.
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 // TODO(adonovan): make this analysis modular: export a mustUseResult
23 // fact for each function that tail-calls one of the functions that we
24 // check, and check those functions too.
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 // flags
42 var funcs, stringMethods stringSetFlag
43
44 func init() {
45         // TODO(adonovan): provide a comment syntax to allow users to
46         // add their functions to this set using facts.
47         funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse,context.WithValue,context.WithCancel,context.WithDeadline,context.WithTimeout")
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 // not a call statement
66                 }
67                 fun := analysisutil.Unparen(call.Fun)
68
69                 if pass.TypesInfo.Types[fun].IsType() {
70                         return // a conversion, not a call
71                 }
72
73                 selector, ok := fun.(*ast.SelectorExpr)
74                 if !ok {
75                         return // neither a method call nor a qualified ident
76                 }
77
78                 sel, ok := pass.TypesInfo.Selections[selector]
79                 if ok && sel.Kind() == types.MethodVal {
80                         // method (e.g. foo.String())
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                         // package-qualified function (e.g. fmt.Errorf)
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 // func() string
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) // clobber previous value
121         if s != "" {
122                 for _, name := range strings.Split(s, ",") {
123                         if name == "" {
124                                 continue // TODO: report error? proceed?
125                         }
126                         m[name] = true
127                 }
128         }
129         *ss = m
130         return nil
131 }