github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/simple/s1019/s1019.go (about) 1 package s1019 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/types" 7 "path/filepath" 8 9 "github.com/amarpal/go-tools/analysis/code" 10 "github.com/amarpal/go-tools/analysis/facts/generated" 11 "github.com/amarpal/go-tools/analysis/lint" 12 "github.com/amarpal/go-tools/analysis/report" 13 "github.com/amarpal/go-tools/go/types/typeutil" 14 "github.com/amarpal/go-tools/pattern" 15 16 "golang.org/x/tools/go/analysis" 17 "golang.org/x/tools/go/analysis/passes/inspect" 18 ) 19 20 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 21 Analyzer: &analysis.Analyzer{ 22 Name: "S1019", 23 Run: run, 24 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer}, 25 }, 26 Doc: &lint.Documentation{ 27 Title: `Simplify \"make\" call by omitting redundant arguments`, 28 Text: `The \"make\" function has default values for the length and capacity 29 arguments. For channels, the length defaults to zero, and for slices, 30 the capacity defaults to the length.`, 31 Since: "2017.1", 32 // MergeIfAll because the type might be different under different build tags. 33 // You shouldn't write code like that… 34 MergeIf: lint.MergeIfAll, 35 }, 36 }) 37 38 var Analyzer = SCAnalyzer.Analyzer 39 40 var ( 41 checkMakeLenCapQ1 = pattern.MustParse(`(CallExpr (Builtin "make") [typ size@(IntegerLiteral "0")])`) 42 checkMakeLenCapQ2 = pattern.MustParse(`(CallExpr (Builtin "make") [typ size size])`) 43 ) 44 45 func run(pass *analysis.Pass) (interface{}, error) { 46 fn := func(node ast.Node) { 47 if pass.Pkg.Path() == "runtime_test" && filepath.Base(pass.Fset.Position(node.Pos()).Filename) == "map_test.go" { 48 // special case of runtime tests testing map creation 49 return 50 } 51 if m, ok := code.Match(pass, checkMakeLenCapQ1, node); ok { 52 T := m.State["typ"].(ast.Expr) 53 size := m.State["size"].(ast.Node) 54 55 if _, ok := typeutil.CoreType(pass.TypesInfo.TypeOf(T)).Underlying().(*types.Chan); ok { 56 report.Report(pass, size, fmt.Sprintf("should use make(%s) instead", report.Render(pass, T)), report.FilterGenerated()) 57 } 58 59 } else if m, ok := code.Match(pass, checkMakeLenCapQ2, node); ok { 60 // TODO(dh): don't consider sizes identical if they're 61 // dynamic. for example: make(T, <-ch, <-ch). 62 T := m.State["typ"].(ast.Expr) 63 size := m.State["size"].(ast.Node) 64 report.Report(pass, size, 65 fmt.Sprintf("should use make(%s, %s) instead", report.Render(pass, T), report.Render(pass, size)), 66 report.FilterGenerated()) 67 } 68 } 69 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 70 return nil, nil 71 }