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.
5 // Package sortslice defines an Analyzer that checks for calls
6 // to sort.Slice that do not use a slice type as first argument.
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"
22 const Doc = `check the argument type of sort.Slice
24 sort.Slice requires an argument of a slice type. Check that
25 the interface{} value passed to sort.Slice is actually a slice.`
27 var Analyzer = &analysis.Analyzer{
30 Requires: []*analysis.Analyzer{inspect.Analyzer},
34 func run(pass *analysis.Pass) (interface{}, error) {
35 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
37 nodeFilter := []ast.Node{
41 inspect.Preorder(nodeFilter, func(n ast.Node) {
42 call := n.(*ast.CallExpr)
43 fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
48 if fn.FullName() != "sort.Slice" {
53 typ := pass.TypesInfo.Types[arg].Type
54 switch typ.Underlying().(type) {
55 case *types.Slice, *types.Interface:
59 var fixes []analysis.SuggestedFix
60 switch v := typ.Underlying().(type) {
63 format.Node(&buf, pass.Fset, &ast.SliceExpr{
66 Lbrack: arg.End() + 1,
67 Rbrack: arg.End() + 3,
69 fixes = append(fixes, analysis.SuggestedFix{
70 Message: "Get a slice of the full array",
71 TextEdits: []analysis.TextEdit{{
78 _, ok := v.Elem().Underlying().(*types.Slice)
83 format.Node(&buf, pass.Fset, &ast.StarExpr{
86 fixes = append(fixes, analysis.SuggestedFix{
87 Message: "Dereference the pointer to the slice",
88 TextEdits: []analysis.TextEdit{{
94 case *types.Signature:
95 if v.Params().Len() != 0 || v.Results().Len() != 1 {
98 if _, ok := v.Results().At(0).Type().Underlying().(*types.Slice); !ok {
102 format.Node(&buf, pass.Fset, &ast.CallExpr{
105 fixes = append(fixes, analysis.SuggestedFix{
106 Message: "Call the function",
107 TextEdits: []analysis.TextEdit{{
110 NewText: buf.Bytes(),
115 pass.Report(analysis.Diagnostic{
118 Message: fmt.Sprintf("sort.Slice's argument must be a slice; is called with %s", typ.String()),
119 SuggestedFixes: fixes,