src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

qf1010.go (1829B)


      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 )
     16 
     17 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     18 	Analyzer: &analysis.Analyzer{
     19 		Name:     "QF1010",
     20 		Run:      run,
     21 		Requires: code.RequiredAnalyzers,
     22 	},
     23 	Doc: &lint.RawDocumentation{
     24 		Title:    "Convert slice of bytes to string when printing it",
     25 		Since:    "2021.1",
     26 		Severity: lint.SeverityHint,
     27 	},
     28 })
     29 
     30 var Analyzer = SCAnalyzer.Analyzer
     31 
     32 var byteSlicePrintingQ = pattern.MustParse(`
     33 	(Or
     34 		(CallExpr
     35 			(Symbol (Or
     36 				"fmt.Print"
     37 				"fmt.Println"
     38 				"fmt.Sprint"
     39 				"fmt.Sprintln"
     40 				"log.Fatal"
     41 				"log.Fatalln"
     42 				"log.Panic"
     43 				"log.Panicln"
     44 				"log.Print"
     45 				"log.Println"
     46 				"(*log.Logger).Fatal"
     47 				"(*log.Logger).Fatalln"
     48 				"(*log.Logger).Panic"
     49 				"(*log.Logger).Panicln"
     50 				"(*log.Logger).Print"
     51 				"(*log.Logger).Println")) args)
     52 
     53 		(CallExpr (Symbol (Or
     54 			"fmt.Fprint"
     55 			"fmt.Fprintln")) _:args))`)
     56 
     57 var byteSlicePrintingR = pattern.MustParse(`(CallExpr (Ident "string") [arg])`)
     58 
     59 func run(pass *analysis.Pass) (any, error) {
     60 	for _, m := range code.Matches(pass, byteSlicePrintingQ) {
     61 		args := m.State["args"].([]ast.Expr)
     62 		for _, arg := range args {
     63 			if !code.IsOfStringConvertibleByteSlice(pass, arg) {
     64 				continue
     65 			}
     66 			if types.Implements(pass.TypesInfo.TypeOf(arg), knowledge.Interfaces["fmt.Stringer"]) {
     67 				continue
     68 			}
     69 
     70 			fix := edit.Fix("Convert argument to string", edit.ReplaceWithPattern(pass.Fset, arg, byteSlicePrintingR, pattern.State{"arg": arg}))
     71 			report.Report(pass, arg, "could convert argument to string", report.Fixes(fix))
     72 		}
     73 	}
     74 	return nil, nil
     75 }