Skip to content

Commit e958370

Browse files
committed
config: adds int conversion option
1 parent 943e3b4 commit e958370

File tree

5 files changed

+649
-10
lines changed

5 files changed

+649
-10
lines changed

analyzer/analyzer.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,27 @@ import (
1414
"golang.org/x/tools/go/analysis"
1515
)
1616

17-
var Analyzer = &analysis.Analyzer{
18-
Name: "perfsprint",
19-
Doc: "Checks that fmt.Sprintf can be replaced with a faster alternative.",
20-
Run: run,
21-
Requires: []*analysis.Analyzer{inspect.Analyzer},
17+
type perfSprint struct {
18+
intConv bool
2219
}
2320

24-
func run(pass *analysis.Pass) (interface{}, error) {
21+
func newPerfSprint() *perfSprint {
22+
return &perfSprint{intConv: true}
23+
}
24+
25+
func New() *analysis.Analyzer {
26+
n := newPerfSprint()
27+
r := &analysis.Analyzer{
28+
Name: "perfsprint",
29+
Doc: "Checks that fmt.Sprintf can be replaced with a faster alternative.",
30+
Run: n.run,
31+
Requires: []*analysis.Analyzer{inspect.Analyzer},
32+
}
33+
r.Flags.BoolVar(&n.intConv, "int-conversion", true, "optimizes even if it needs an int conversion")
34+
return r
35+
}
36+
37+
func (n *perfSprint) run(pass *analysis.Pass) (interface{}, error) {
2538
var fmtSprintObj, fmtSprintfObj types.Object
2639
for _, pkg := range pass.Pkg.Imports() {
2740
if pkg.Path() == "fmt" {
@@ -184,7 +197,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
184197
},
185198
}
186199

187-
case isBasicType(valueType, types.Int8, types.Int16, types.Int32) && oneOf(verb, "%v", "%d"):
200+
case isBasicType(valueType, types.Int8, types.Int16, types.Int32) && oneOf(verb, "%v", "%d") && n.intConv:
188201
d = &analysis.Diagnostic{
189202
Pos: call.Pos(),
190203
End: call.End(),
@@ -247,7 +260,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
247260
},
248261
}
249262

250-
case isBasicType(valueType, types.Uint8, types.Uint16, types.Uint32, types.Uint) && oneOf(verb, "%v", "%d"):
263+
case isBasicType(valueType, types.Uint8, types.Uint16, types.Uint32, types.Uint) && oneOf(verb, "%v", "%d") && n.intConv:
251264
d = &analysis.Diagnostic{
252265
Pos: call.Pos(),
253266
End: call.End(),

analyzer/analyzer_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,17 @@ import (
1313

1414
func TestAnalyzer(t *testing.T) {
1515
t.Parallel()
16-
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), analyzer.Analyzer, "p")
16+
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), analyzer.New(), "p")
17+
}
18+
19+
func TestAnalyzerNoConv(t *testing.T) {
20+
t.Parallel()
21+
a := analyzer.New()
22+
err := a.Flags.Set("int-conversion", "false")
23+
if err != nil {
24+
t.Fatalf("failed to set int-conversion flag")
25+
}
26+
analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), a, "noconv")
1727
}
1828

1929
func TestReplacements(t *testing.T) {

analyzer/testdata/src/noconv/p.go

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
package noconv
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
)
8+
9+
var errSentinel = errors.New("connection refused")
10+
11+
func positive() {
12+
var i int
13+
var i8 int8
14+
var i16 int16
15+
var i32 int32
16+
var i64 int64
17+
fmt.Sprintf("%d", i) // want "fmt.Sprintf can be replaced with faster strconv.Itoa"
18+
fmt.Sprintf("%v", i) // want "fmt.Sprintf can be replaced with faster strconv.Itoa"
19+
fmt.Sprint(i) // want "fmt.Sprint can be replaced with faster strconv.Itoa"
20+
fmt.Sprintf("%d", 42) // want "fmt.Sprintf can be replaced with faster strconv.Itoa"
21+
fmt.Sprintf("%v", 42) // want "fmt.Sprintf can be replaced with faster strconv.Itoa"
22+
fmt.Sprint(42) // want "fmt.Sprint can be replaced with faster strconv.Itoa"
23+
fmt.Sprintf("%d", i8)
24+
fmt.Sprintf("%v", i8)
25+
fmt.Sprint(i8)
26+
fmt.Sprintf("%d", int8(42))
27+
fmt.Sprintf("%v", int8(42))
28+
fmt.Sprint(int8(42))
29+
fmt.Sprintf("%d", i16)
30+
fmt.Sprintf("%v", i16)
31+
fmt.Sprint(i16)
32+
fmt.Sprintf("%d", int16(42))
33+
fmt.Sprintf("%v", int16(42))
34+
fmt.Sprint(int16(42))
35+
fmt.Sprintf("%d", i32)
36+
fmt.Sprintf("%v", i32)
37+
fmt.Sprint(i32)
38+
fmt.Sprintf("%d", int32(42))
39+
fmt.Sprintf("%v", int32(42))
40+
fmt.Sprint(int32(42))
41+
fmt.Sprintf("%d", i64) // want "fmt.Sprintf can be replaced with faster strconv.FormatInt"
42+
fmt.Sprintf("%v", i64) // want "fmt.Sprintf can be replaced with faster strconv.FormatInt"
43+
fmt.Sprint(i64) // want "fmt.Sprint can be replaced with faster strconv.FormatInt"
44+
fmt.Sprintf("%d", int64(42)) // want "fmt.Sprintf can be replaced with faster strconv.FormatInt"
45+
fmt.Sprintf("%v", int64(42)) // want "fmt.Sprintf can be replaced with faster strconv.FormatInt"
46+
fmt.Sprint(int64(42)) // want "fmt.Sprint can be replaced with faster strconv.FormatInt"
47+
48+
var ui uint
49+
var ui8 uint8
50+
var ui16 uint16
51+
var ui32 uint32
52+
var ui64 uint64
53+
fmt.Sprintf("%d", ui)
54+
fmt.Sprintf("%v", ui)
55+
fmt.Sprint(ui)
56+
fmt.Sprintf("%d", uint(42))
57+
fmt.Sprintf("%v", uint(42))
58+
fmt.Sprint(uint(42))
59+
fmt.Sprintf("%d", ui8)
60+
fmt.Sprintf("%v", ui8)
61+
fmt.Sprint(ui8)
62+
fmt.Sprintf("%d", uint8(42))
63+
fmt.Sprintf("%v", uint8(42))
64+
fmt.Sprint(uint8(42))
65+
fmt.Sprintf("%d", ui16)
66+
fmt.Sprintf("%v", ui16)
67+
fmt.Sprint(ui16)
68+
fmt.Sprintf("%d", uint16(42))
69+
fmt.Sprintf("%v", uint16(42))
70+
fmt.Sprint(uint16(42))
71+
fmt.Sprintf("%d", ui32)
72+
fmt.Sprintf("%v", ui32)
73+
fmt.Sprint(ui32)
74+
fmt.Sprintf("%d", uint32(42))
75+
fmt.Sprintf("%v", uint32(42))
76+
fmt.Sprint(uint32(42))
77+
fmt.Sprintf("%d", ui64) // want "fmt.Sprintf can be replaced with faster strconv.FormatUint"
78+
fmt.Sprintf("%v", ui64) // want "fmt.Sprintf can be replaced with faster strconv.FormatUint"
79+
fmt.Sprint(ui64) // want "fmt.Sprint can be replaced with faster strconv.FormatUint"
80+
fmt.Sprintf("%d", uint64(42)) // want "fmt.Sprintf can be replaced with faster strconv.FormatUint"
81+
fmt.Sprintf("%v", uint64(42)) // want "fmt.Sprintf can be replaced with faster strconv.FormatUint"
82+
fmt.Sprint(uint64(42)) // want "fmt.Sprint can be replaced with faster strconv.FormatUint"
83+
}
84+
85+
func negative() {
86+
const val = "val%d"
87+
88+
_ = int32(42)
89+
90+
fmt.Scan(42)
91+
fmt.Scanf("%d", 42)
92+
fmt.Println("%d", 42)
93+
fmt.Printf("%d")
94+
fmt.Printf("%v")
95+
fmt.Printf("%d", 42)
96+
fmt.Printf("%s %d", "hello", 42)
97+
98+
fmt.Fprint(os.Stdout, "%d", 42)
99+
fmt.Fprintf(os.Stdout, "test")
100+
fmt.Fprintf(os.Stdout, "%d")
101+
fmt.Fprintf(os.Stdout, "%v")
102+
fmt.Fprintf(os.Stdout, "%d", 42)
103+
fmt.Fprintf(os.Stdout, "%s %d", "hello", 42)
104+
105+
fmt.Sprint("test", 42)
106+
fmt.Sprint(42, 42)
107+
fmt.Sprintf("test")
108+
fmt.Sprintf("%v")
109+
fmt.Sprintf("%d")
110+
fmt.Sprintf("%d", 42, 42)
111+
fmt.Sprintf("%#d", 42)
112+
fmt.Sprintf("value %d", 42)
113+
fmt.Sprintf(val, 42)
114+
fmt.Sprintf("%s %v", "hello", "world")
115+
fmt.Sprintf("%#v", 42)
116+
fmt.Sprintf("%T", struct{ string }{})
117+
fmt.Sprintf("%%v", 42)
118+
fmt.Sprintf("%3d", 42)
119+
fmt.Sprintf("% d", 42)
120+
fmt.Sprintf("%-10d", 42)
121+
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
122+
fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6)
123+
fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
124+
125+
// Integer.
126+
fmt.Sprintf("%#x", uint64(42))
127+
fmt.Sprintf("%#v", uint64(42))
128+
fmt.Sprintf("%#b", 42)
129+
fmt.Sprintf("%#o", 42)
130+
fmt.Sprintf("%#x", 42)
131+
fmt.Sprintf("%#X", 42)
132+
133+
fmt.Sprintf("%b", 42)
134+
fmt.Sprintf("%c", 42)
135+
fmt.Sprintf("%o", 42)
136+
fmt.Sprintf("%O", 42)
137+
fmt.Sprintf("%q", 42)
138+
fmt.Sprintf("%x", 42)
139+
fmt.Sprintf("%X", 42)
140+
141+
// Floating point.
142+
fmt.Sprintf("%9f", 42.42)
143+
fmt.Sprintf("%.2f", 42.42)
144+
fmt.Sprintf("%.2f", 42.42)
145+
fmt.Sprintf("%9.2f", 42.42)
146+
fmt.Sprintf("%9.f", 42.42)
147+
fmt.Sprintf("%.3g", 42.42)
148+
149+
fmt.Sprintf("%b", float32(42.42))
150+
fmt.Sprintf("%e", float32(42.42))
151+
fmt.Sprintf("%E", float32(42.42))
152+
fmt.Sprintf("%f", float32(42.42))
153+
fmt.Sprintf("%F", float32(42.42))
154+
fmt.Sprintf("%g", float32(42.42))
155+
fmt.Sprintf("%G", float32(42.42))
156+
fmt.Sprintf("%x", float32(42.42))
157+
fmt.Sprintf("%X", float32(42.42))
158+
fmt.Sprintf("%v", float32(42.42))
159+
160+
fmt.Sprintf("%b", 42.42)
161+
fmt.Sprintf("%e", 42.42)
162+
fmt.Sprintf("%E", 42.42)
163+
fmt.Sprintf("%f", 42.42)
164+
fmt.Sprintf("%F", 42.42)
165+
fmt.Sprintf("%g", 42.42)
166+
fmt.Sprintf("%G", 42.42)
167+
fmt.Sprintf("%x", 42.42)
168+
fmt.Sprintf("%X", 42.42)
169+
fmt.Sprintf("%v", 42.42)
170+
171+
fmt.Sprintf("%b", 42i+42)
172+
fmt.Sprintf("%e", 42i+42)
173+
fmt.Sprintf("%E", 42i+42)
174+
fmt.Sprintf("%f", 42i+42)
175+
fmt.Sprintf("%F", 42i+42)
176+
fmt.Sprintf("%g", 42i+42)
177+
fmt.Sprintf("%G", 42i+42)
178+
fmt.Sprintf("%x", 42i+42)
179+
fmt.Sprintf("%X", 42i+42)
180+
fmt.Sprintf("%v", 42i+42)
181+
182+
// String & slice of bytes.
183+
fmt.Sprintf("%q", "hello")
184+
fmt.Sprintf("%#q", `"hello"`)
185+
fmt.Sprintf("%+q", "hello")
186+
fmt.Sprintf("%X", "hello")
187+
188+
// Slice.
189+
fmt.Sprintf("%x", []uint16{'d'})
190+
fmt.Sprintf("%x", []uint32{'d'})
191+
fmt.Sprintf("%x", []uint64{'d'})
192+
fmt.Sprintf("%x", []uint{'d'})
193+
fmt.Sprintf("%x", [1]byte{'c'})
194+
fmt.Sprintf("%x", [1]uint8{'d'})
195+
fmt.Sprintf("%x", [1]uint16{'d'})
196+
fmt.Sprintf("%x", [1]uint32{'d'})
197+
fmt.Sprintf("%x", [1]uint64{'d'})
198+
fmt.Sprintf("%x", [1]uint{'d'})
199+
fmt.Sprintf("%x", []int8{1})
200+
fmt.Sprintf("%x", []int16{1})
201+
fmt.Sprintf("%x", []int32{1})
202+
fmt.Sprintf("%x", []int64{1})
203+
fmt.Sprintf("%x", []int{1})
204+
fmt.Sprintf("%x", [...]int8{1})
205+
fmt.Sprintf("%x", [...]int16{1})
206+
fmt.Sprintf("%x", [...]int32{1})
207+
fmt.Sprintf("%x", [...]int64{1})
208+
fmt.Sprintf("%x", [...]int{1})
209+
fmt.Sprintf("%x", []string{"hello"})
210+
fmt.Sprintf("%x", []rune{'a'})
211+
212+
fmt.Sprintf("% x", []byte{1, 2, 3})
213+
fmt.Sprintf("% X", []byte{1, 2, 3})
214+
fmt.Sprintf("%p", []byte{1, 2, 3})
215+
fmt.Sprintf("%#p", []byte{1, 2, 3})
216+
217+
// Pointer.
218+
var ptr *int
219+
fmt.Sprintf("%v", ptr)
220+
fmt.Sprintf("%b", ptr)
221+
fmt.Sprintf("%d", ptr)
222+
fmt.Sprintf("%o", ptr)
223+
fmt.Sprintf("%x", ptr)
224+
fmt.Sprintf("%X", ptr)
225+
}
226+
227+
func malformed() {
228+
fmt.Sprintf("%d", "example")
229+
fmt.Sprintf("%T", "example")
230+
fmt.Sprintf("%t", "example")
231+
fmt.Sprintf("%b", "example")
232+
fmt.Sprintf("%e", "example")
233+
fmt.Sprintf("%E", "example")
234+
fmt.Sprintf("%f", "example")
235+
fmt.Sprintf("%F", "example")
236+
fmt.Sprintf("%g", "example")
237+
fmt.Sprintf("%G", "example")
238+
fmt.Sprintf("%x", "example")
239+
fmt.Sprintf("%X", "example")
240+
241+
fmt.Sprintf("%d", errSentinel)
242+
fmt.Sprintf("%T", errSentinel)
243+
fmt.Sprintf("%t", errSentinel)
244+
fmt.Sprintf("%b", errSentinel)
245+
fmt.Sprintf("%e", errSentinel)
246+
fmt.Sprintf("%E", errSentinel)
247+
fmt.Sprintf("%f", errSentinel)
248+
fmt.Sprintf("%F", errSentinel)
249+
fmt.Sprintf("%g", errSentinel)
250+
fmt.Sprintf("%G", errSentinel)
251+
fmt.Sprintf("%x", errSentinel)
252+
fmt.Sprintf("%X", errSentinel)
253+
254+
fmt.Sprintf("%d", true)
255+
fmt.Sprintf("%T", true)
256+
fmt.Sprintf("%b", true)
257+
fmt.Sprintf("%e", true)
258+
fmt.Sprintf("%E", true)
259+
fmt.Sprintf("%f", true)
260+
fmt.Sprintf("%F", true)
261+
fmt.Sprintf("%g", true)
262+
fmt.Sprintf("%G", true)
263+
fmt.Sprintf("%x", true)
264+
fmt.Sprintf("%X", true)
265+
266+
var bb []byte
267+
fmt.Sprintf("%d", bb)
268+
fmt.Sprintf("%T", bb)
269+
fmt.Sprintf("%t", bb)
270+
fmt.Sprintf("%b", bb)
271+
fmt.Sprintf("%e", bb)
272+
fmt.Sprintf("%E", bb)
273+
fmt.Sprintf("%f", bb)
274+
fmt.Sprintf("%F", bb)
275+
fmt.Sprintf("%g", bb)
276+
fmt.Sprintf("%G", bb)
277+
fmt.Sprintf("%X", bb)
278+
fmt.Sprintf("%v", bb)
279+
280+
fmt.Sprintf("%T", 42)
281+
fmt.Sprintf("%t", 42)
282+
fmt.Sprintf("%b", 42)
283+
fmt.Sprintf("%e", 42)
284+
fmt.Sprintf("%E", 42)
285+
fmt.Sprintf("%f", 42)
286+
fmt.Sprintf("%F", 42)
287+
fmt.Sprintf("%g", 42)
288+
fmt.Sprintf("%G", 42)
289+
fmt.Sprintf("%x", 42)
290+
fmt.Sprintf("%X", 42)
291+
292+
fmt.Sprintf("%T", uint(42))
293+
fmt.Sprintf("%t", uint(42))
294+
fmt.Sprintf("%b", uint(42))
295+
fmt.Sprintf("%e", uint(42))
296+
fmt.Sprintf("%E", uint(42))
297+
fmt.Sprintf("%f", uint(42))
298+
fmt.Sprintf("%F", uint(42))
299+
fmt.Sprintf("%g", uint(42))
300+
fmt.Sprintf("%G", uint(42))
301+
fmt.Sprintf("%x", uint(42))
302+
fmt.Sprintf("%X", uint(42))
303+
304+
fmt.Sprintf("%d", 42.42)
305+
fmt.Sprintf("%d", map[string]string{})
306+
fmt.Sprint(make(chan int))
307+
fmt.Sprint([]int{1, 2, 3})
308+
}

0 commit comments

Comments
 (0)