Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / analysis / unusedparams / unusedparams.go
1 // Copyright 2020 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 unusedparams defines an analyzer that checks for unused
6 // parameters of functions.
7 package unusedparams
8
9 import (
10         "fmt"
11         "go/ast"
12         "go/types"
13         "strings"
14
15         "golang.org/x/tools/go/analysis"
16         "golang.org/x/tools/go/analysis/passes/inspect"
17         "golang.org/x/tools/go/ast/inspector"
18 )
19
20 const Doc = `check for unused parameters of functions
21
22 The unusedparams analyzer checks functions to see if there are
23 any parameters that are not being used.
24
25 To reduce false positives it ignores:
26 - methods
27 - parameters that do not have a name or are underscored
28 - functions in test files
29 - functions with empty bodies or those with just a return stmt`
30
31 var Analyzer = &analysis.Analyzer{
32         Name:     "unusedparams",
33         Doc:      Doc,
34         Requires: []*analysis.Analyzer{inspect.Analyzer},
35         Run:      run,
36 }
37
38 type paramData struct {
39         field  *ast.Field
40         ident  *ast.Ident
41         typObj types.Object
42 }
43
44 func run(pass *analysis.Pass) (interface{}, error) {
45         inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
46         nodeFilter := []ast.Node{
47                 (*ast.FuncDecl)(nil),
48                 (*ast.FuncLit)(nil),
49         }
50
51         inspect.Preorder(nodeFilter, func(n ast.Node) {
52                 var fieldList *ast.FieldList
53                 var body *ast.BlockStmt
54
55                 // Get the fieldList and body from the function node.
56                 switch f := n.(type) {
57                 case *ast.FuncDecl:
58                         fieldList, body = f.Type.Params, f.Body
59                         // TODO(golang/go#36602): add better handling for methods, if we enable methods
60                         // we will get false positives if a struct is potentially implementing
61                         // an interface.
62                         if f.Recv != nil {
63                                 return
64                         }
65                         // Ignore functions in _test.go files to reduce false positives.
66                         if file := pass.Fset.File(n.Pos()); file != nil && strings.HasSuffix(file.Name(), "_test.go") {
67                                 return
68                         }
69                 case *ast.FuncLit:
70                         fieldList, body = f.Type.Params, f.Body
71                 }
72                 // If there are no arguments or the function is empty, then return.
73                 if fieldList.NumFields() == 0 || len(body.List) == 0 {
74                         return
75                 }
76
77                 switch expr := body.List[0].(type) {
78                 case *ast.ReturnStmt:
79                         // Ignore functions that only contain a return statement to reduce false positives.
80                         return
81                 case *ast.ExprStmt:
82                         callExpr, ok := expr.X.(*ast.CallExpr)
83                         if !ok || len(body.List) > 1 {
84                                 break
85                         }
86                         // Ignore functions that only contain a panic statement to reduce false positives.
87                         if fun, ok := callExpr.Fun.(*ast.Ident); ok && fun.Name == "panic" {
88                                 return
89                         }
90                 }
91
92                 // Get the useful data from each field.
93                 params := make(map[string]*paramData)
94                 unused := make(map[*paramData]bool)
95                 for _, f := range fieldList.List {
96                         for _, i := range f.Names {
97                                 if i.Name == "_" {
98                                         continue
99                                 }
100                                 params[i.Name] = &paramData{
101                                         field:  f,
102                                         ident:  i,
103                                         typObj: pass.TypesInfo.ObjectOf(i),
104                                 }
105                                 unused[params[i.Name]] = true
106                         }
107                 }
108
109                 // Traverse through the body of the function and
110                 // check to see which parameters are unused.
111                 ast.Inspect(body, func(node ast.Node) bool {
112                         n, ok := node.(*ast.Ident)
113                         if !ok {
114                                 return true
115                         }
116                         param, ok := params[n.Name]
117                         if !ok {
118                                 return false
119                         }
120                         if nObj := pass.TypesInfo.ObjectOf(n); nObj != param.typObj {
121                                 return false
122                         }
123                         delete(unused, param)
124                         return false
125                 })
126
127                 // Create the reports for the unused parameters.
128                 for u := range unused {
129                         start, end := u.field.Pos(), u.field.End()
130                         if len(u.field.Names) > 1 {
131                                 start, end = u.ident.Pos(), u.ident.End()
132                         }
133                         // TODO(golang/go#36602): Add suggested fixes to automatically
134                         // remove the unused parameter. To start, just remove it from the
135                         // function declaration. Later, remove it from every use of this
136                         // function.
137                         pass.Report(analysis.Diagnostic{
138                                 Pos:     start,
139                                 End:     end,
140                                 Message: fmt.Sprintf("potentially unused parameter: '%s'", u.ident.Name),
141                         })
142                 }
143         })
144         return nil, nil
145 }