honnef.co/go/tools@v0.5.0-0.dev.0.20240520180541-dcae280a5e87/quickfix/qf1010/qf1010.go (about) 1 package qf1010 2 3 import ( 4 "go/ast" 5 "go/types" 6 7 "honnef.co/go/tools/analysis/code" 8 "honnef.co/go/tools/analysis/edit" 9 "honnef.co/go/tools/analysis/lint" 10 "honnef.co/go/tools/analysis/report" 11 "honnef.co/go/tools/knowledge" 12 "honnef.co/go/tools/pattern" 13 14 "golang.org/x/tools/go/analysis" 15 "golang.org/x/tools/go/analysis/passes/inspect" 16 ) 17 18 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 19 Analyzer: &analysis.Analyzer{ 20 Name: "QF1010", 21 Run: run, 22 Requires: []*analysis.Analyzer{inspect.Analyzer}, 23 }, 24 Doc: &lint.Documentation{ 25 Title: "Convert slice of bytes to string when printing it", 26 Since: "2021.1", 27 Severity: lint.SeverityHint, 28 }, 29 }) 30 31 var Analyzer = SCAnalyzer.Analyzer 32 33 var byteSlicePrintingQ = pattern.MustParse(` 34 (Or 35 (CallExpr 36 (Symbol (Or 37 "fmt.Print" 38 "fmt.Println" 39 "fmt.Sprint" 40 "fmt.Sprintln" 41 "log.Fatal" 42 "log.Fatalln" 43 "log.Panic" 44 "log.Panicln" 45 "log.Print" 46 "log.Println" 47 "(*log.Logger).Fatal" 48 "(*log.Logger).Fatalln" 49 "(*log.Logger).Panic" 50 "(*log.Logger).Panicln" 51 "(*log.Logger).Print" 52 "(*log.Logger).Println")) args) 53 54 (CallExpr (Symbol (Or 55 "fmt.Fprint" 56 "fmt.Fprintln")) _:args))`) 57 58 var byteSlicePrintingR = pattern.MustParse(`(CallExpr (Ident "string") [arg])`) 59 60 func run(pass *analysis.Pass) (interface{}, error) { 61 fn := func(node ast.Node) { 62 m, ok := code.Match(pass, byteSlicePrintingQ, node) 63 if !ok { 64 return 65 } 66 args := m.State["args"].([]ast.Expr) 67 for _, arg := range args { 68 if !code.IsOfStringConvertibleByteSlice(pass, arg) { 69 continue 70 } 71 if types.Implements(pass.TypesInfo.TypeOf(arg), knowledge.Interfaces["fmt.Stringer"]) { 72 continue 73 } 74 75 fix := edit.Fix("Convert argument to string", edit.ReplaceWithPattern(pass.Fset, arg, byteSlicePrintingR, pattern.State{"arg": arg})) 76 report.Report(pass, arg, "could convert argument to string", report.Fixes(fix)) 77 } 78 } 79 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 80 return nil, nil 81 }