diff --git a/analyzer/analyzer.go b/analyzer/analyzer.go index 75a1fb8..97b477a 100644 --- a/analyzer/analyzer.go +++ b/analyzer/analyzer.go @@ -162,18 +162,16 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { removedFmtUsages[fname]++ if fn == "fmt.Errorf" { neededPackages[fname]["errors"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with errors.New", - []analysis.SuggestedFix{ + fn, + "errors.New", + []analysis.TextEdit{ { - Message: "Use errors.New", - TextEdits: []analysis.TextEdit{{ - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("errors.New("), - }}, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("errors.New("), }, }, ) @@ -200,18 +198,16 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { errMethodCall := formatNode(pass.Fset, value) + ".Error()" fname := pass.Fset.File(call.Pos()).Name() removedFmtUsages[fname]++ - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with "+errMethodCall, - []analysis.SuggestedFix{ + fn, + errMethodCall, + []analysis.TextEdit{ { - Message: "Use " + errMethodCall, - TextEdits: []analysis.TextEdit{{ - Pos: call.Pos(), - End: call.End(), - NewText: []byte(errMethodCall), - }}, + Pos: call.Pos(), + End: call.End(), + NewText: []byte(errMethodCall), }, }, ) @@ -223,18 +219,16 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["strconv"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster strconv.FormatBool", - []analysis.SuggestedFix{ + fn, + "strconv.FormatBool", + []analysis.TextEdit{ { - Message: "Use strconv.FormatBool", - TextEdits: []analysis.TextEdit{{ - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("strconv.FormatBool("), - }}, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("strconv.FormatBool("), }, }, ) @@ -251,25 +245,21 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["encoding/hex"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster hex.EncodeToString", - []analysis.SuggestedFix{ + fn, + "hex.EncodeToString", + []analysis.TextEdit{ { - Message: "Use hex.EncodeToString", - TextEdits: []analysis.TextEdit{ - { - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("hex.EncodeToString("), - }, - { - Pos: value.End(), - End: value.End(), - NewText: []byte("[:]"), - }, - }, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("hex.EncodeToString("), + }, + { + Pos: value.End(), + End: value.End(), + NewText: []byte("[:]"), }, }, ) @@ -280,18 +270,16 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["encoding/hex"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster hex.EncodeToString", - []analysis.SuggestedFix{ + fn, + "hex.EncodeToString", + []analysis.TextEdit{ { - Message: "Use hex.EncodeToString", - TextEdits: []analysis.TextEdit{{ - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("hex.EncodeToString("), - }}, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("hex.EncodeToString("), }, }, ) @@ -303,25 +291,21 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["strconv"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster strconv.Itoa", - []analysis.SuggestedFix{ + fn, + "strconv.Itoa", + []analysis.TextEdit{ { - Message: "Use strconv.Itoa", - TextEdits: []analysis.TextEdit{ - { - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("strconv.Itoa(int("), - }, - { - Pos: value.End(), - End: value.End(), - NewText: []byte(")"), - }, - }, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("strconv.Itoa(int("), + }, + { + Pos: value.End(), + End: value.End(), + NewText: []byte(")"), }, }, ) @@ -332,18 +316,16 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["strconv"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster strconv.Itoa", - []analysis.SuggestedFix{ + fn, + "strconv.Itoa", + []analysis.TextEdit{ { - Message: "Use strconv.Itoa", - TextEdits: []analysis.TextEdit{{ - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("strconv.Itoa("), - }}, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("strconv.Itoa("), }, }, ) @@ -354,25 +336,21 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["strconv"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster strconv.FormatInt", - []analysis.SuggestedFix{ + fn, + "strconv.FormatInt", + []analysis.TextEdit{ { - Message: "Use strconv.FormatInt", - TextEdits: []analysis.TextEdit{ - { - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("strconv.FormatInt("), - }, - { - Pos: value.End(), - End: value.End(), - NewText: []byte(", 10"), - }, - }, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("strconv.FormatInt("), + }, + { + Pos: value.End(), + End: value.End(), + NewText: []byte(", 10"), }, }, ) @@ -388,25 +366,21 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["strconv"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster strconv.FormatUint", - []analysis.SuggestedFix{ + fn, + "strconv.FormatUint", + []analysis.TextEdit{ { - Message: "Use strconv.FormatUint", - TextEdits: []analysis.TextEdit{ - { - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("strconv.FormatUint(uint64("), - }, - { - Pos: value.End(), - End: value.End(), - NewText: base, - }, - }, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("strconv.FormatUint(uint64("), + }, + { + Pos: value.End(), + End: value.End(), + NewText: base, }, }, ) @@ -421,25 +395,21 @@ func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) { neededPackages[fname] = make(map[string]struct{}) } neededPackages[fname]["strconv"] = struct{}{} - d = newAnalysisDiagnostic( + d = newFasterFunctionReplacementDiagnostic( "", // TODO: precise checker call, - fn+" can be replaced with faster strconv.FormatUint", - []analysis.SuggestedFix{ + fn, + "strconv.FormatUint", + []analysis.TextEdit{ { - Message: "Use strconv.FormatUint", - TextEdits: []analysis.TextEdit{ - { - Pos: call.Pos(), - End: value.Pos(), - NewText: []byte("strconv.FormatUint("), - }, - { - Pos: value.End(), - End: value.End(), - NewText: base, - }, - }, + Pos: call.Pos(), + End: value.Pos(), + NewText: []byte("strconv.FormatUint("), + }, + { + Pos: value.End(), + End: value.End(), + NewText: base, }, }, ) diff --git a/analyzer/diagnostic.go b/analyzer/diagnostic.go index 9384c6e..5cc79b1 100644 --- a/analyzer/diagnostic.go +++ b/analyzer/diagnostic.go @@ -23,3 +23,23 @@ func newAnalysisDiagnostic( } return &d } + +func newFasterFunctionReplacementDiagnostic( + checker string, + analysisRange analysis.Range, + function string, + suggestedFunction string, + textEdits []analysis.TextEdit, +) *analysis.Diagnostic { + return newAnalysisDiagnostic( + checker, + analysisRange, + function+" can be replaced with faster "+suggestedFunction, + []analysis.SuggestedFix{ + { + Message: "Use " + suggestedFunction, + TextEdits: textEdits, + }, + }, + ) +} diff --git a/analyzer/testdata/src/p/p.go b/analyzer/testdata/src/p/p.go index 9989dd9..cbf929b 100644 --- a/analyzer/testdata/src/p/p.go +++ b/analyzer/testdata/src/p/p.go @@ -22,22 +22,22 @@ func positive() { fmt.Sprintf("%[1]s", s) // want "fmt.Sprintf can be replaced with just using the string" fmt.Sprintf("%v", s) // want "fmt.Sprintf can be replaced with just using the string" fmt.Sprint(s) // want "fmt.Sprint can be replaced with just using the string" - fmt.Errorf("hello") // want "fmt.Errorf can be replaced with errors.New" + fmt.Errorf("hello") // want "fmt.Errorf can be replaced with faster errors.New" fmt.Sprintf("Hello %s", s) // want "fmt.Sprintf can be replaced with string concatenation" fmt.Sprintf("%s says Hello", s) // want "fmt.Sprintf can be replaced with string concatenation" fmt.Sprintf("Hello says %[1]s", s) // want "fmt.Sprintf can be replaced with string concatenation" var err error - fmt.Sprintf("%s", errSentinel) // want "fmt.Sprintf can be replaced with errSentinel.Error()" - fmt.Sprintf("%v", errSentinel) // want "fmt.Sprintf can be replaced with errSentinel.Error()" - fmt.Sprint(errSentinel) // want "fmt.Sprint can be replaced with errSentinel.Error()" - fmt.Sprintf("%s", io.EOF) // want "fmt.Sprintf can be replaced with io.EOF.Error()" - fmt.Sprintf("%v", io.EOF) // want "fmt.Sprintf can be replaced with io.EOF.Error()" - fmt.Sprint(io.EOF) // want "fmt.Sprint can be replaced with io.EOF.Error()" - fmt.Sprintf("%s", err) // want "fmt.Sprintf can be replaced with err.Error()" - fmt.Sprintf("%v", err) // want "fmt.Sprintf can be replaced with err.Error()" - fmt.Sprint(err) // want "fmt.Sprint can be replaced with err.Error()" + fmt.Sprintf("%s", errSentinel) // want "fmt.Sprintf can be replaced with faster errSentinel.Error()" + fmt.Sprintf("%v", errSentinel) // want "fmt.Sprintf can be replaced with faster errSentinel.Error()" + fmt.Sprint(errSentinel) // want "fmt.Sprint can be replaced with faster errSentinel.Error()" + fmt.Sprintf("%s", io.EOF) // want "fmt.Sprintf can be replaced with faster io.EOF.Error()" + fmt.Sprintf("%v", io.EOF) // want "fmt.Sprintf can be replaced with faster io.EOF.Error()" + fmt.Sprint(io.EOF) // want "fmt.Sprint can be replaced with faster io.EOF.Error()" + fmt.Sprintf("%s", err) // want "fmt.Sprintf can be replaced with faster err.Error()" + fmt.Sprintf("%v", err) // want "fmt.Sprintf can be replaced with faster err.Error()" + fmt.Sprint(err) // want "fmt.Sprint can be replaced with faster err.Error()" var b bool fmt.Sprintf("%t", true) // want "fmt.Sprintf can be replaced with faster strconv.FormatBool" @@ -140,8 +140,8 @@ func suggestedFixesTest() { return fmt.Sprintf("%s", "replace me") // want "fmt.Sprintf can be replaced with just using the string" } - fmt.Println(fmt.Sprint(errSentinel)) // want "fmt.Sprint can be replaced with errSentinel.Error()" - fmt.Println(fmt.Sprintf("%s", errSentinel)) // want "fmt.Sprintf can be replaced with errSentinel.Error()" + fmt.Println(fmt.Sprint(errSentinel)) // want "fmt.Sprint can be replaced with faster errSentinel.Error()" + fmt.Println(fmt.Sprintf("%s", errSentinel)) // want "fmt.Sprintf can be replaced with faster errSentinel.Error()" _ = func() string { switch 42 { diff --git a/analyzer/testdata/src/p/p.go.golden b/analyzer/testdata/src/p/p.go.golden index b8982c7..cd9b280 100644 --- a/analyzer/testdata/src/p/p.go.golden +++ b/analyzer/testdata/src/p/p.go.golden @@ -24,22 +24,22 @@ func positive() { s // want "fmt.Sprintf can be replaced with just using the string" s // want "fmt.Sprintf can be replaced with just using the string" s // want "fmt.Sprint can be replaced with just using the string" - errors.New("hello") // want "fmt.Errorf can be replaced with errors.New" + errors.New("hello") // want "fmt.Errorf can be replaced with faster errors.New" "Hello " + s // want "fmt.Sprintf can be replaced with string concatenation" s + " says Hello" // want "fmt.Sprintf can be replaced with string concatenation" "Hello says " + s // want "fmt.Sprintf can be replaced with string concatenation" var err error - errSentinel.Error() // want "fmt.Sprintf can be replaced with errSentinel.Error()" - errSentinel.Error() // want "fmt.Sprintf can be replaced with errSentinel.Error()" - errSentinel.Error() // want "fmt.Sprint can be replaced with errSentinel.Error()" - io.EOF.Error() // want "fmt.Sprintf can be replaced with io.EOF.Error()" - io.EOF.Error() // want "fmt.Sprintf can be replaced with io.EOF.Error()" - io.EOF.Error() // want "fmt.Sprint can be replaced with io.EOF.Error()" - err.Error() // want "fmt.Sprintf can be replaced with err.Error()" - err.Error() // want "fmt.Sprintf can be replaced with err.Error()" - err.Error() // want "fmt.Sprint can be replaced with err.Error()" + errSentinel.Error() // want "fmt.Sprintf can be replaced with faster errSentinel.Error()" + errSentinel.Error() // want "fmt.Sprintf can be replaced with faster errSentinel.Error()" + errSentinel.Error() // want "fmt.Sprint can be replaced with faster errSentinel.Error()" + io.EOF.Error() // want "fmt.Sprintf can be replaced with faster io.EOF.Error()" + io.EOF.Error() // want "fmt.Sprintf can be replaced with faster io.EOF.Error()" + io.EOF.Error() // want "fmt.Sprint can be replaced with faster io.EOF.Error()" + err.Error() // want "fmt.Sprintf can be replaced with faster err.Error()" + err.Error() // want "fmt.Sprintf can be replaced with faster err.Error()" + err.Error() // want "fmt.Sprint can be replaced with faster err.Error()" var b bool strconv.FormatBool(true) // want "fmt.Sprintf can be replaced with faster strconv.FormatBool" @@ -142,8 +142,8 @@ func suggestedFixesTest() { return "replace me" // want "fmt.Sprintf can be replaced with just using the string" } - fmt.Println(errSentinel.Error()) // want "fmt.Sprint can be replaced with errSentinel.Error()" - fmt.Println(errSentinel.Error()) // want "fmt.Sprintf can be replaced with errSentinel.Error()" + fmt.Println(errSentinel.Error()) // want "fmt.Sprint can be replaced with faster errSentinel.Error()" + fmt.Println(errSentinel.Error()) // want "fmt.Sprintf can be replaced with faster errSentinel.Error()" _ = func() string { switch 42 {