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 / go / analysis / passes / sortslice / analyzer.go
1 // Copyright 2019 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 sortslice defines an Analyzer that checks for calls
6 // to sort.Slice that do not use a slice type as first argument.
7 package sortslice
8
9 import (
10         "bytes"
11         "fmt"
12         "go/ast"
13         "go/format"
14         "go/types"
15
16         "golang.org/x/tools/go/analysis"
17         "golang.org/x/tools/go/analysis/passes/inspect"
18         "golang.org/x/tools/go/ast/inspector"
19         "golang.org/x/tools/go/types/typeutil"
20 )
21
22 const Doc = `check the argument type of sort.Slice
23
24 sort.Slice requires an argument of a slice type. Check that
25 the interface{} value passed to sort.Slice is actually a slice.`
26
27 var Analyzer = &analysis.Analyzer{
28         Name:     "sortslice",
29         Doc:      Doc,
30         Requires: []*analysis.Analyzer{inspect.Analyzer},
31         Run:      run,
32 }
33
34 func run(pass *analysis.Pass) (interface{}, error) {
35         inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
36
37         nodeFilter := []ast.Node{
38                 (*ast.CallExpr)(nil),
39         }
40
41         inspect.Preorder(nodeFilter, func(n ast.Node) {
42                 call := n.(*ast.CallExpr)
43                 fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
44                 if fn == nil {
45                         return
46                 }
47
48                 if fn.FullName() != "sort.Slice" {
49                         return
50                 }
51
52                 arg := call.Args[0]
53                 typ := pass.TypesInfo.Types[arg].Type
54                 switch typ.Underlying().(type) {
55                 case *types.Slice, *types.Interface:
56                         return
57                 }
58
59                 var fixes []analysis.SuggestedFix
60                 switch v := typ.Underlying().(type) {
61                 case *types.Array:
62                         var buf bytes.Buffer
63                         format.Node(&buf, pass.Fset, &ast.SliceExpr{
64                                 X:      arg,
65                                 Slice3: false,
66                                 Lbrack: arg.End() + 1,
67                                 Rbrack: arg.End() + 3,
68                         })
69                         fixes = append(fixes, analysis.SuggestedFix{
70                                 Message: "Get a slice of the full array",
71                                 TextEdits: []analysis.TextEdit{{
72                                         Pos:     arg.Pos(),
73                                         End:     arg.End(),
74                                         NewText: buf.Bytes(),
75                                 }},
76                         })
77                 case *types.Pointer:
78                         _, ok := v.Elem().Underlying().(*types.Slice)
79                         if !ok {
80                                 break
81                         }
82                         var buf bytes.Buffer
83                         format.Node(&buf, pass.Fset, &ast.StarExpr{
84                                 X: arg,
85                         })
86                         fixes = append(fixes, analysis.SuggestedFix{
87                                 Message: "Dereference the pointer to the slice",
88                                 TextEdits: []analysis.TextEdit{{
89                                         Pos:     arg.Pos(),
90                                         End:     arg.End(),
91                                         NewText: buf.Bytes(),
92                                 }},
93                         })
94                 case *types.Signature:
95                         if v.Params().Len() != 0 || v.Results().Len() != 1 {
96                                 break
97                         }
98                         if _, ok := v.Results().At(0).Type().Underlying().(*types.Slice); !ok {
99                                 break
100                         }
101                         var buf bytes.Buffer
102                         format.Node(&buf, pass.Fset, &ast.CallExpr{
103                                 Fun: arg,
104                         })
105                         fixes = append(fixes, analysis.SuggestedFix{
106                                 Message: "Call the function",
107                                 TextEdits: []analysis.TextEdit{{
108                                         Pos:     arg.Pos(),
109                                         End:     arg.End(),
110                                         NewText: buf.Bytes(),
111                                 }},
112                         })
113                 }
114
115                 pass.Report(analysis.Diagnostic{
116                         Pos:            call.Pos(),
117                         End:            call.End(),
118                         Message:        fmt.Sprintf("sort.Slice's argument must be a slice; is called with %s", typ.String()),
119                         SuggestedFixes: fixes,
120                 })
121         })
122         return nil, nil
123 }