src

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

s1039.go (1903B)


      1 package s1039
      2 
      3 import (
      4 	"fmt"
      5 	"go/ast"
      6 	"go/types"
      7 	"strings"
      8 
      9 	"honnef.co/go/tools/analysis/code"
     10 	"honnef.co/go/tools/analysis/edit"
     11 	"honnef.co/go/tools/analysis/facts/generated"
     12 	"honnef.co/go/tools/analysis/lint"
     13 	"honnef.co/go/tools/analysis/report"
     14 	"honnef.co/go/tools/pattern"
     15 
     16 	"golang.org/x/tools/go/analysis"
     17 )
     18 
     19 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
     20 	Analyzer: &analysis.Analyzer{
     21 		Name:     "S1039",
     22 		Run:      run,
     23 		Requires: append([]*analysis.Analyzer{generated.Analyzer}, code.RequiredAnalyzers...),
     24 	},
     25 	Doc: &lint.RawDocumentation{
     26 		Title: `Unnecessary use of \'fmt.Sprint\'`,
     27 		Text: `
     28 Calling \'fmt.Sprint\' with a single string argument is unnecessary
     29 and identical to using the string directly.`,
     30 		Since: "2020.1",
     31 		// MergeIfAll because s might not be a string under all build tags.
     32 		// you shouldn't write code like that…
     33 		MergeIf: lint.MergeIfAll,
     34 	},
     35 })
     36 
     37 var Analyzer = SCAnalyzer.Analyzer
     38 
     39 var checkSprintLiteralQ = pattern.MustParse(`
     40 	(CallExpr
     41 		fn@(Or
     42 			(Symbol "fmt.Sprint")
     43 			(Symbol "fmt.Sprintf"))
     44 		[lit@(BasicLit "STRING" _)])`)
     45 
     46 func run(pass *analysis.Pass) (any, error) {
     47 	// We only flag calls with string literals, not expressions of
     48 	// type string, because some people use fmt.Sprint(s) as a pattern
     49 	// for copying strings, which may be useful when extracting a small
     50 	// substring from a large string.
     51 
     52 	for node, m := range code.Matches(pass, checkSprintLiteralQ) {
     53 		callee := m.State["fn"].(*types.Func)
     54 		lit := m.State["lit"].(*ast.BasicLit)
     55 		if callee.Name() == "Sprintf" {
     56 			if strings.ContainsRune(lit.Value, '%') {
     57 				// This might be a format string
     58 				continue
     59 			}
     60 		}
     61 		report.Report(pass, node, fmt.Sprintf("unnecessary use of fmt.%s", callee.Name()),
     62 			report.FilterGenerated(),
     63 			report.Fixes(edit.Fix("Replace with string literal", edit.ReplaceWithNode(pass.Fset, node, lit))))
     64 	}
     65 	return nil, nil
     66 }