Skip to content

Commit 161c639

Browse files
committed
feat(lint): use more accurate config
1 parent 6e7f857 commit 161c639

18 files changed

Lines changed: 158 additions & 72 deletions

.golangci.yml

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,97 @@ formatters:
88
linters:
99
default: none
1010
enable:
11-
- errcheck
12-
- staticcheck
13-
- govet
14-
- ineffassign
15-
- unused
16-
- misspell
17-
- unconvert
18-
- revive
11+
# --- Bug & correctness ---
12+
- errcheck # unchecked error returns
13+
- govet # go vet suspicious constructs
14+
- staticcheck # comprehensive static analysis
15+
- nilerr # returning nil where error is expected
16+
- bodyclose # unclosed HTTP response bodies (factory/img.go)
17+
18+
# --- Code quality ---
19+
- ineffassign # useless assignments
20+
- unused # unused code
21+
- unconvert # unnecessary type conversions
22+
- wastedassign # overwritten-before-read assignments
23+
- copyloopvar # loop variable capture issues
24+
25+
# --- Performance ---
26+
- prealloc # slice pre-allocation hints
27+
- mirror # bytes/strings mirror-function suggestions
28+
- perfsprint # faster fmt.Sprintf alternatives
29+
30+
# --- Style & consistency ---
31+
- revive # superset of golint
32+
- misspell # common English misspellings
33+
- dupword # duplicate words in comments / strings
34+
- whitespace # unnecessary leading/trailing blank lines
35+
- goprintffuncname # printf-like functions end with 'f'
36+
- gocritic # opinionated but high-signal checks
37+
- asciicheck # non-ASCII identifiers
38+
- bidichk # dangerous bidi unicode sequences
39+
40+
# --- Security ---
41+
- gosec # security-oriented checks
42+
43+
# --- Modernization ---
44+
- intrange # for i := 0; i < n; i++ → for i := range n
45+
- usestdlibvars # prefer stdlib constants (http.StatusOK, etc.)
46+
- modernize # suggest modern Go idioms
47+
48+
settings:
49+
gocritic:
50+
enabled-tags:
51+
- diagnostic
52+
- performance
53+
disabled-checks:
54+
- hugeParam # graphics functions pass large structs by value on purpose
55+
- rangeValCopy # same reason
56+
- whyNoLint # not using nolint directives
57+
- commentedOutCode # example/test files legitimately keep commented-out alternatives
58+
59+
gosec:
60+
excludes:
61+
- G103 # unsafe.Pointer — intentional for pixel manipulation and GPU interop
62+
- G107 # HTTP request with variable URL — expected for image loading from URLs
63+
- G115 # integer overflow conversion — deliberate in pixel/color math
64+
- G304 # file path from variable — this IS an image-loading library
65+
- G306 # poor file permissions — not applicable
66+
- G401 # weak crypto (md5) — used only for display hashing, not security
67+
- G404 # weak RNG — used for k-means color quantization, not security
68+
- G501 # blocklisted import crypto/md5 — same as G401
69+
70+
revive:
71+
rules:
72+
- name: blank-imports
73+
- name: context-as-argument
74+
- name: dot-imports
75+
- name: error-return
76+
- name: error-strings
77+
- name: error-naming
78+
- name: exported
79+
- name: increment-decrement
80+
- name: indent-error-flow
81+
- name: package-comments
82+
- name: range
83+
- name: receiver-naming
84+
- name: time-naming
85+
- name: unexported-return
86+
- name: unreachable-code
87+
- name: unused-parameter
88+
- name: superfluous-else
89+
90+
prealloc:
91+
simple: true
92+
for-loops: false # avoid false positives in complex rendering loops
93+
1994
exclusions:
2095
rules:
96+
# Exclude non-Go sources from typecheck
2197
- path: \.cpp$
2298
linters:
2399
- typecheck
100+
101+
# cmd/ is not part of the library API — relax everything
24102
- path: ^cmd/
25103
linters:
26104
- errcheck
@@ -31,10 +109,19 @@ linters:
31109
- misspell
32110
- unconvert
33111
- revive
112+
113+
# Deferred close errors are almost never actionable
34114
- linters:
35115
- errcheck
36116
source: "^\\s*defer "
37117

118+
# Test files: relax security, pre-alloc, and HTTP body checks
119+
- path: _test\.go$
120+
linters:
121+
- gosec
122+
- prealloc
123+
- bodyclose
124+
38125
issues:
39126
max-issues-per-linter: 0
40127
max-same-issues: 0

color.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func takecolor(img image.Image, k int) []color.RGBA {
3636

3737
// 初始化k个聚类中心
3838
clusters := make([]color.RGBA, k)
39-
for i := 0; i < k; i++ {
39+
for i := range k {
4040
clusters[i] = pixels[rand.Intn(len(pixels))]
4141
}
4242

@@ -57,7 +57,7 @@ func takecolor(img image.Image, k int) []color.RGBA {
5757

5858
// 计算每个聚类的新中心
5959
newClusters := make([]color.RGBA, k)
60-
for i := 0; i < k; i++ {
60+
for i := range k {
6161
var r, g, b uint32
6262
n := 0
6363
for j, cluster := range clusterAssignments {
@@ -99,7 +99,7 @@ func clustersEqual(a, b []color.RGBA) bool {
9999
if len(a) != len(b) {
100100
return false
101101
}
102-
for i := 0; i < len(a); i++ {
102+
for i := range a {
103103
if a[i] != b[i] {
104104
return false
105105
}

color_test.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313
// solidImage 创建一个全部填充为指定颜色的 image.Image
1414
func solidImage(w, h int, c color.RGBA) image.Image {
1515
img := image.NewRGBA(image.Rect(0, 0, w, h))
16-
for y := 0; y < h; y++ {
17-
for x := 0; x < w; x++ {
16+
for y := range h {
17+
for x := range w {
1818
img.SetRGBA(x, y, c)
1919
}
2020
}
@@ -24,8 +24,8 @@ func solidImage(w, h int, c color.RGBA) image.Image {
2424
// twoColorImage 创建左半部分为 c1、右半部分为 c2 的图像
2525
func twoColorImage(w, h int, c1, c2 color.RGBA) image.Image {
2626
img := image.NewRGBA(image.Rect(0, 0, w, h))
27-
for y := 0; y < h; y++ {
28-
for x := 0; x < w; x++ {
27+
for y := range h {
28+
for x := range w {
2929
if x < w/2 {
3030
img.SetRGBA(x, y, c1)
3131
} else {
@@ -135,7 +135,7 @@ func TestDistance_Symmetry(t *testing.T) {
135135

136136
func TestDistance_NonNegative(t *testing.T) {
137137
rng := rand.New(rand.NewSource(42))
138-
for i := 0; i < 100; i++ {
138+
for range 100 {
139139
a := color.RGBA{uint8(rng.Intn(256)), uint8(rng.Intn(256)), uint8(rng.Intn(256)), 255}
140140
b := color.RGBA{uint8(rng.Intn(256)), uint8(rng.Intn(256)), uint8(rng.Intn(256)), 255}
141141
got := distance(a, b)
@@ -263,7 +263,7 @@ func TestTakecolor_TwoDistinctColors(t *testing.T) {
263263
// 多次运行,验证算法至少能在 30 次尝试中有一次正确分离两种颜色。
264264
img := twoColorImage(20, 20, Red, Blue)
265265
const maxAttempts = 30
266-
for attempt := 0; attempt < maxAttempts; attempt++ {
266+
for range maxAttempts {
267267
result := takecolor(img, 2)
268268
if len(result) == 2 && colorInSlice(Red, result, 5) && colorInSlice(Blue, result, 5) {
269269
return // 成功分离,测试通过
@@ -286,8 +286,8 @@ func TestTakecolor_Deterministic_SolidImage(t *testing.T) {
286286
func TestTakecolor_AllClustersHaveValidRGB(t *testing.T) {
287287
rng := rand.New(rand.NewSource(99))
288288
img := image.NewRGBA(image.Rect(0, 0, 16, 16))
289-
for y := 0; y < 16; y++ {
290-
for x := 0; x < 16; x++ {
289+
for y := range 16 {
290+
for x := range 16 {
291291
img.SetRGBA(x, y, color.RGBA{
292292
uint8(rng.Intn(256)),
293293
uint8(rng.Intn(256)),
@@ -310,7 +310,7 @@ func TestTakecolor_AllClustersHaveValidRGB(t *testing.T) {
310310
// ---- Benchmark ----
311311

312312
func BenchmarkSq(b *testing.B) {
313-
for i := 0; i < b.N; i++ {
313+
for i := range b.N {
314314
sq(float64(i))
315315
}
316316
}
@@ -319,7 +319,7 @@ func BenchmarkDistance(b *testing.B) {
319319
a := color.RGBA{100, 150, 200, 255}
320320
c := color.RGBA{50, 80, 30, 255}
321321
b.ResetTimer()
322-
for i := 0; i < b.N; i++ {
322+
for range b.N {
323323
distance(a, c)
324324
}
325325
}
@@ -328,7 +328,7 @@ func BenchmarkClustersEqual_Equal(b *testing.B) {
328328
a := []color.RGBA{{255, 0, 0, 255}, {0, 255, 0, 255}, {0, 0, 255, 255}, {128, 128, 128, 255}}
329329
c := []color.RGBA{{255, 0, 0, 255}, {0, 255, 0, 255}, {0, 0, 255, 255}, {128, 128, 128, 255}}
330330
b.ResetTimer()
331-
for i := 0; i < b.N; i++ {
331+
for range b.N {
332332
clustersEqual(a, c)
333333
}
334334
}
@@ -337,57 +337,57 @@ func BenchmarkClustersEqual_NotEqual(b *testing.B) {
337337
a := []color.RGBA{{255, 0, 0, 255}, {0, 255, 0, 255}, {0, 0, 255, 255}, {128, 128, 128, 255}}
338338
c := []color.RGBA{{255, 0, 0, 255}, {0, 255, 0, 255}, {0, 0, 255, 255}, {200, 200, 200, 255}}
339339
b.ResetTimer()
340-
for i := 0; i < b.N; i++ {
340+
for range b.N {
341341
clustersEqual(a, c)
342342
}
343343
}
344344

345345
func BenchmarkTakecolor_16x16_K3(b *testing.B) {
346346
rng := rand.New(rand.NewSource(42))
347347
img := image.NewRGBA(image.Rect(0, 0, 16, 16))
348-
for y := 0; y < 16; y++ {
349-
for x := 0; x < 16; x++ {
348+
for y := range 16 {
349+
for x := range 16 {
350350
img.SetRGBA(x, y, color.RGBA{uint8(rng.Intn(256)), uint8(rng.Intn(256)), uint8(rng.Intn(256)), 255})
351351
}
352352
}
353353
b.ResetTimer()
354-
for i := 0; i < b.N; i++ {
354+
for range b.N {
355355
takecolor(img, 3)
356356
}
357357
}
358358

359359
func BenchmarkTakecolor_64x64_K4(b *testing.B) {
360360
rng := rand.New(rand.NewSource(42))
361361
img := image.NewRGBA(image.Rect(0, 0, 64, 64))
362-
for y := 0; y < 64; y++ {
363-
for x := 0; x < 64; x++ {
362+
for y := range 64 {
363+
for x := range 64 {
364364
img.SetRGBA(x, y, color.RGBA{uint8(rng.Intn(256)), uint8(rng.Intn(256)), uint8(rng.Intn(256)), 255})
365365
}
366366
}
367367
b.ResetTimer()
368-
for i := 0; i < b.N; i++ {
368+
for range b.N {
369369
takecolor(img, 4)
370370
}
371371
}
372372

373373
func BenchmarkTakecolor_128x128_K8(b *testing.B) {
374374
rng := rand.New(rand.NewSource(42))
375375
img := image.NewRGBA(image.Rect(0, 0, 128, 128))
376-
for y := 0; y < 128; y++ {
377-
for x := 0; x < 128; x++ {
376+
for y := range 128 {
377+
for x := range 128 {
378378
img.SetRGBA(x, y, color.RGBA{uint8(rng.Intn(256)), uint8(rng.Intn(256)), uint8(rng.Intn(256)), 255})
379379
}
380380
}
381381
b.ResetTimer()
382-
for i := 0; i < b.N; i++ {
382+
for range b.N {
383383
takecolor(img, 8)
384384
}
385385
}
386386

387387
func BenchmarkTakecolor_SolidColor_K5(b *testing.B) {
388388
img := solidImage(64, 64, color.RGBA{200, 100, 50, 255})
389389
b.ResetTimer()
390-
for i := 0; i < b.N; i++ {
390+
for range b.N {
391391
takecolor(img, 5)
392392
}
393393
}

context.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ func (dc *Context) DrawRoundedRectangle(x, y, w, h, r float64) {
930930
// DrawEllipticalArc 绘制以 (x, y) 为中心的椭圆弧。
931931
func (dc *Context) DrawEllipticalArc(x, y, rx, ry, angle1, angle2 float64) {
932932
const n = 16
933-
for i := 0; i < n; i++ {
933+
for i := range n {
934934
p1 := float64(i+0) / n
935935
p2 := float64(i+1) / n
936936
a1 := angle1 + (angle2-angle1)*p1
@@ -989,7 +989,7 @@ func (dc *Context) DrawRegularPolygon(n int, x, y, r, rotation float64) {
989989
rotation += angle / 2
990990
}
991991
dc.NewSubPath()
992-
for i := 0; i < n; i++ {
992+
for i := range n {
993993
a := rotation + angle*float64(i)
994994
dc.LineTo(x+r*math.Cos(a), y+r*math.Sin(a))
995995
}
@@ -1000,7 +1000,7 @@ func (dc *Context) DrawRegularPolygon(n int, x, y, r, rotation float64) {
10001000
//
10011001
// LoadImage 从指定路径加载图像并绘制到 (x, y) 坐标。
10021002
func (dc *Context) LoadImage(path string, x, y int) error {
1003-
img, err := fio.LoadImage(path) //添加图片
1003+
img, err := fio.LoadImage(path) // 添加图片
10041004
if err != nil {
10051005
return err
10061006
}

0 commit comments

Comments
 (0)