github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/cmd/tast-lint/internal/check/func_parameters.go (about) 1 // Copyright 2020 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 "bytes" 9 "go/ast" 10 "go/format" 11 "go/token" 12 13 "golang.org/x/tools/go/ast/astutil" 14 ) 15 16 // FuncParams checks function parameters and results. 17 func FuncParams(fs *token.FileSet, f *ast.File, fix bool) (issues []*Issue) { 18 astutil.Apply(f, func(c *astutil.Cursor) (cont bool) { 19 // Always continue traversal. 20 cont = true 21 22 n, ok := c.Node().(*ast.FuncType) 23 if !ok { 24 return 25 } 26 for _, l := range []*ast.FieldList{n.Params, n.Results} { 27 if l == nil || l.List == nil || l.List[0].Names == nil { 28 continue 29 } 30 var nfis []*ast.Field 31 var names []*ast.Ident 32 var prev *ast.Field 33 var removable []ast.Expr 34 for _, fi := range l.List { 35 if prev == nil { 36 names = append(names, fi.Names...) 37 prev = fi 38 continue 39 } 40 // This seems to be always false (i.e. all the fields in 41 // non-nil prev are nil). We have it to be on the safe side. 42 shouldSeparate := prev.Doc != nil || prev.Tag != nil || prev.Comment != nil 43 if shouldSeparate || !sameType(fs, prev.Type, fi.Type) { 44 nfis = append(nfis, &ast.Field{ 45 Doc: prev.Doc, 46 Names: names, 47 Type: prev.Type, 48 Tag: prev.Tag, 49 Comment: prev.Comment, 50 }) 51 names = nil 52 } else { 53 removable = append(removable, prev.Type) 54 } 55 names = append(names, fi.Names...) 56 prev = fi 57 } 58 nfis = append(nfis, &ast.Field{ 59 Doc: prev.Doc, 60 Names: names, 61 Type: prev.Type, 62 Tag: prev.Tag, 63 Comment: prev.Comment, 64 }) 65 if fix { 66 l.List = nfis 67 } else { 68 for _, t := range removable { 69 issues = append(issues, &Issue{ 70 Pos: fs.Position(t.Pos()), 71 Msg: "When two or more consecutive named function parameters share a type, you can omit the type from all but the last", 72 Link: "https://tour.golang.org/basics/5", 73 Fixable: true, 74 }) 75 } 76 } 77 } 78 return 79 }, nil) 80 return 81 } 82 83 // sameType returns whether x and y have the same string representation. 84 // Both x and y should be representing a type. 85 func sameType(fs *token.FileSet, x, y ast.Expr) bool { 86 var xb bytes.Buffer 87 if err := format.Node(&xb, fs, x); err != nil { 88 return false 89 } 90 var yb bytes.Buffer 91 if err := format.Node(&yb, fs, y); err != nil { 92 return false 93 } 94 return xb.String() == yb.String() 95 }