github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/cmd/tast-lint/internal/check/define_emptyslice.go (about) 1 // Copyright 2019 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package check 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/token" 11 "strings" 12 13 "golang.org/x/tools/go/ast/astutil" 14 ) 15 16 // EmptySlice warns the invalid empty slice declaration. 17 func EmptySlice(fs *token.FileSet, f *ast.File, fix bool) []*Issue { 18 var issues []*Issue 19 20 // Traverse a syntax tree and find not-preferred empty slice declarations. 21 astutil.Apply(f, func(c *astutil.Cursor) bool { 22 // If parent is not a block statement, ignore. 23 // - For example, empty slice assginment in the statement like 24 // `if a := []int{}; len(a) == 1 { // parent is ast.IfStmt 25 // return 26 // }` 27 // is not replacable by 'var' statement. 28 if _, ok := c.Parent().(*ast.BlockStmt); !ok { 29 return true 30 } 31 32 asgn, ok := c.Node().(*ast.AssignStmt) 33 if !ok { 34 return true 35 } 36 if asgn.Tok != token.DEFINE { 37 return true 38 } 39 40 // Find invalid empty slice declarations. 41 var ids []*ast.Ident 42 var elt ast.Expr 43 44 for i, rexp := range asgn.Rhs { 45 comp, ok := rexp.(*ast.CompositeLit) 46 if !ok { 47 continue 48 } 49 50 arr, ok := comp.Type.(*ast.ArrayType) 51 if !ok { 52 continue 53 } 54 55 if arr.Len == nil && comp.Elts == nil { 56 id, ok := asgn.Lhs[i].(*ast.Ident) 57 if !ok { 58 continue 59 } 60 61 ids = append(ids, id) 62 elt = arr.Elt 63 } 64 } 65 66 if len(ids) == 0 { 67 return true 68 } 69 70 fixable := len(asgn.Rhs) == 1 71 if !fix { 72 var idNames []string 73 for _, id := range ids { 74 idNames = append(idNames, id.Name) 75 } 76 issue := &Issue{ 77 Pos: fs.Position(asgn.Pos()), 78 Msg: fmt.Sprintf("Use 'var' statement when you declare empty slice(s): %s", strings.Join(idNames, ", ")), 79 Link: "https://github.com/golang/go/wiki/CodeReviewComments#declaring-empty-slices", 80 Fixable: fixable, 81 } 82 issues = append(issues, issue) 83 } else if fix && fixable { 84 c.Replace(&ast.DeclStmt{ 85 Decl: &ast.GenDecl{ 86 Tok: token.VAR, 87 TokPos: ids[0].NamePos, 88 Specs: []ast.Spec{ 89 &ast.ValueSpec{ 90 Names: ids, 91 Type: &ast.ArrayType{ 92 Elt: elt, 93 }, 94 }, 95 }, 96 }, 97 }) 98 } 99 100 return true 101 }, nil) 102 103 return issues 104 }