一些Go静态分析工具

其他语言的分析工具:

https://github.com/Ericsson/codechecker

姊妹篇:

Go静态代码检查工具GolangCI-Lint



golangci-lint这个项目想把这些静态工具汇总到一起


1
2
3
4
5
6
7
8
golangci-lint run --no-config --disable-all  -E goconst  ./...

panic: load embedded ruleguard rules: rules/rules.go:13: can't load fmt

goroutine 1 [running]:
github.com/go-critic/go-critic/checkers.init.22()
/Users/fliter/go/pkg/mod/github.com/go-critic/go-critic@v0.6.3/checkers/embedded_rules.go:47 +0x494


再次提醒一下,Go工具的1.18支持一定是需要重新使用最新版本编译,否则可能会出现报错等等各种问题。
比如gopls不重新编译会无法正常提示泛型相关;比如golangci-lint如果使用非go install安装,一般是老版本Go编译,会提示panic: load embedded ruleguard rules: rules/rules.go:13: can’t load fmt    来自推文



我之前是用 brew install golangci-lint安装的,如果用go install/go get则没这个问题。

go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.53.3

虽然golangci-lin官方不推荐,还煞有介事给出了几条理由:

1
2
3
4
5
6
7
8
9
go install/go get installation isn't recommended because of the following points:

1. some users use -u flag for go get, which upgrades our dependencies. Resulting configuration wasn't tested and isn't guaranteed to work.
2. go.mod replacement directive doesn't apply. It means a user will be using patched version of golangci-lint if we use such replacements.
3. it's stability depends on a user's Go version (e.g. on this compiler Go <= 1.12 bug).
4. we've encountered a lot of issues with Go modules hashes.
5. it allows installation from master branch which can't be considered stable.
6. it's slower than binary installation


golangci-lint–Linters

好多使用golangci-lint发挥不出作用,有各种问题。

但可以查看其作用,对感兴趣的点击链接,跳到其github仓库,按介绍安装


durationcheck


检查两个持续时间是否相乘

https://www.reddit.com/r/golang/comments/asff5s/durationcheck_a_linter_to_detect_incorrect_usage/


用低版本的go构建(例如我在命令行中),去到高版本的环境中(如scp到某台服务器上,或者在GoLand的命令行中),会报错。

所以最好在高版本的go环境下执行 go install github.com/charithe/durationcheck/cmd/durationcheck@latest


如果还是有错误,直接rm /Users/fliter/go/bin/durationcheck,用当前的go版本重新go install github.com/charithe/durationcheck/cmd/durationcheck@latest


另外所有的项目都要进行 go mod init xxx && go mod tidy,否则也会报错


写一个shell脚本,遍历当前文件夹下的各个独立项目,执行go mod init shuang678 && go mod tidy (即便之前已经有go.mod,也只是会报 go: /xx/xxxxx/go.mod already exists,不影响目的)

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

set +e # 关闭错误退出功能

# 遍历当前目录下所有文件夹
for dir in */ ; do
cd "$dir" # 进入文件夹
go mod init shuang678 # 初始化 go.mod 文件
go mod tidy # 整理依赖
cd .. # 回到上级目录
done

https://github.com/prometheus/prometheus/pull/12550/files

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
func (g *Group) run(ctx context.Context) {
defer close(g.terminated)

// Wait an initial amount to have consistently slotted intervals.
evalTimestamp := g.EvalTimestamp(time.Now().UnixNano()).Add(g.interval)
select {
case <-time.After(time.Until(evalTimestamp)):
case <-g.done:
return
}

ctx = promql.NewOriginContext(ctx, map[string]interface{}{
"ruleGroup": map[string]string{
"file": g.File(),
"name": g.Name(),
},
})

// The assumption here is that since the ticker was started after having
// waited for `evalTimestamp` to pass, the ticks will trigger soon
// after each `evalTimestamp + N * g.interval` occurrence.
tick := time.NewTicker(g.interval)
defer tick.Stop()

defer func() {
if !g.markStale {
return
}
go func(now time.Time) {
for _, rule := range g.seriesInPreviousEval {
for _, r := range rule {
g.staleSeries = append(g.staleSeries, r)
}
}
// That can be garbage collected at this point.
g.seriesInPreviousEval = nil
// Wait for 2 intervals to give the opportunity to renamed rules
// to insert new series in the tsdb. At this point if there is a
// renamed rule, it should already be started.
select {
case <-g.managerDone:
case <-time.After(2 * g.interval):
g.cleanupStaleSeries(ctx, now)
}
}(time.Now())
}()

g.evalIterationFunc(ctx, g, evalTimestamp)
if g.shouldRestore {
// If we have to restore, we wait for another Eval to finish.
// The reason behind this is, during first eval (or before it)
// we might not have enough data scraped, and recording rules would not
// have updated the latest values, on which some alerts might depend.
select {
case <-g.done:
return
case <-tick.C:
missed := (time.Since(evalTimestamp) / g.interval) - 1
if missed > 0 {
g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
}
evalTimestamp = evalTimestamp.Add((missed + 1) * g.interval)
g.evalIterationFunc(ctx, g, evalTimestamp)
}

g.RestoreForState(time.Now())
g.shouldRestore = false
}

for {
select {
case <-g.done:
return
default:
select {
case <-g.done:
return
case <-tick.C:
missed := (time.Since(evalTimestamp) / g.interval) - 1
if missed > 0 {
g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
}
evalTimestamp = evalTimestamp.Add((missed + 1) * g.interval)

g.evalIterationFunc(ctx, g, evalTimestamp)
}
}
}
} 这段代码有两个time.Duration类型的值相乘了,是不是有问题?如何改正

是的,该代码中存在两个time.Duration类型的值相乘的操作,这在语义上可能不符合预期。time.Duration类型表示时间的持续时间,它使用纳秒为单位。因此,将两个time.Duration值相乘将导致时间的持续时间增加,这可能不是代码作者的意图。

如果要避免这种问题,可以使用适当的乘法操作来解决。在这种情况下,需要将time.Duration值转换为整数,执行乘法操作,然后将结果转换回time.Duration类型。

以下是对代码进行修改,解决两个time.Duration值相乘的问题:

1
2
3
4
5
6
7
missed := int(time.Since(evalTimestamp) / g.interval) - 1
if missed > 0 {
missedDuration := time.Duration(missed) * g.interval
g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(missedDuration.Seconds())
g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(missedDuration.Seconds())
}
evalTimestamp = evalTimestamp.Add(time.Duration(missed+1) * g.interval)

在上述修改中,我们首先将missed转换为整数,然后使用整数乘法计算出错过的时间持续时间。将其添加到指标中时,我们将其转换为秒进行计算,以适应指标的单位。

然后,我们将整数乘以g.interval进行计算,并将结果转换回time.Duration类型,以获得正确的时间持续时间。最后,我们使用更新后的evalTimestamp继续进行计算。

请注意,这只是一个示例修改,具体修改取决于您的需求和代码的上下文。确保根据具体情况进行适当的调整。



dupword


检测重复单词,这个很实用,感觉也不难实现:我已经能获取到所有评论,只要比对某个单词和其下一个单词是否一致即可~

其核心代码:https://github.com/Abirdcfly/dupword/blob/main/dupword.go#L88

go install github.com/Abirdcfly/dupword/cmd/dupword@latest

dupword ./...

K8s项目检测到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/Users/fliter/video-tmp/kubernetes/cluster/images/etcd/migrate/data_dir.go:167:21: Duplicate words (to) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/types.go:3859:2: Duplicate words (LoadBalancer) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/types.go:5659:2: Duplicate words (P) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/types.go:5694:2: Duplicate words (P) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/types.go:5723:2: Duplicate words (P) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/apps/types.go:610:2: Duplicate words (during) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/garbagecollector/graph_builder.go:87:2: Duplicate words (after) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/storage/types.go:606:2: Duplicate words (be) found
/Users/fliter/video-tmp/kubernetes/plugin/pkg/auth/authorizer/node/graph.go:77:1: Duplicate words (pod) found
/Users/fliter/video-tmp/kubernetes/plugin/pkg/auth/authorizer/node/graph.go:79:1: Duplicate words (pv) found
/Users/fliter/video-tmp/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go:209:4: Duplicate words (information) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/certificates/types.go:74:2: Duplicate words (and) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/networking/types.go:485:1: Duplicate words (where) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/batch/types.go:514:2: Duplicate words (new) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/volume.go:289:2: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/pkg/controlplane/controller/clusterauthenticationtrust/cluster_authentication_trust_controller.go:206:2: Duplicate words (that) found
/Users/fliter/video-tmp/kubernetes/pkg/registry/core/service/ipallocator/allocator.go:77:1: Duplicate words (r.base) found
/Users/fliter/video-tmp/kubernetes/pkg/registry/core/service/storage/alloc.go:214:4: Duplicate words (than) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:3760:21: Duplicate words (during) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:6408:21: Duplicate words (during) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:12780:21: Duplicate words (new) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:13586:21: Duplicate words (new) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:13949:21: Duplicate words (and) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:14272:21: Duplicate words (and) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:22099:21: Duplicate words (of) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:25687:21: Duplicate words (P) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:25703:21: Duplicate words (P) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:25717:21: Duplicate words (P) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:28505:18: Duplicate words (where) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:29949:21: Duplicate words (during) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:33450:18: Duplicate words (where) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:34593:18: Duplicate words (where) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:39577:21: Duplicate words (be) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:40165:21: Duplicate words (be) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:40907:21: Duplicate words (be) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:44173:18: Duplicate words (that) found
/Users/fliter/video-tmp/kubernetes/pkg/generated/openapi/zz_generated.openapi.go:44181:18: Duplicate words (that) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/endpoint/endpoints_controller.go:239:4: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/pkg/util/goroutinemap/exponentialbackoff/exponential_backoff.go:102:1: Duplicate words (returned) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/util/operationexecutor/operation_generator.go:1161:4: Duplicate words (is) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/volume/ephemeral/controller.go:67:2: Duplicate words (indexer) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/awsebs/aws_ebs_block.go:61:2: Duplicate words (globalMapPath) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/awsebs/aws_util.go:303:2: Duplicate words (vol-1234) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/azuredd/azure_dd_block.go:62:2: Duplicate words (globalMapPath) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/fc/fc.go:308:2: Duplicate words (globalMapPathUUID) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/gcepd/gce_pd_block.go:64:2: Duplicate words (globalMapPath) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/iscsi/iscsi.go:294:2: Duplicate words (globalMapPathUUID) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/iscsi/iscsi.go:658:2: Duplicate words (globalMapPath) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/rbd/rbd.go:454:2: Duplicate words (globalMapPath) found
/Users/fliter/video-tmp/kubernetes/pkg/volume/vsphere_volume/vsphere_volume_block.go:59:2: Duplicate words (globalMapPath) found
/Users/fliter/video-tmp/kubernetes/pkg/proxy/ipvs/graceful_termination.go:70:1: Duplicate words (remove) found
/Users/fliter/video-tmp/kubernetes/pkg/scheduler/internal/cache/interface.go:37:1: Duplicate words (v) found
/Users/fliter/video-tmp/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests.go:205:3: Duplicate words (localhost) found
/Users/fliter/video-tmp/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests.go:130:16: Duplicate words (run) found
/Users/fliter/video-tmp/kubernetes/cmd/kubeadm/app/phases/etcd/local.go:272:15: Duplicate words (run) found
/Users/fliter/video-tmp/kubernetes/cmd/kubeadm/app/cmd/completion.go:143:23: Duplicate words (fi,shift) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/topologymanager/policy.go:320:3: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/pluginmanager/cache/types.go:34:1: Duplicate words (v) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/pluginmanager/cache/types.go:35:1: Duplicate words (Out) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/volumemanager/cache/actual_state_of_world.go:458:2: Duplicate words (at) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/kubelet_pods.go:375:3: Duplicate words (podIPs) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/pod_workers.go:919:5: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/test/e2e/framework/framework.go:129:1: Duplicate words (with) found
/Users/fliter/video-tmp/kubernetes/test/e2e/framework/log.go:83:2: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/test/e2e/common/node/container_probe.go:664:8: Duplicate words (script) found
/Users/fliter/video-tmp/kubernetes/test/e2e/common/node/container_probe.go:676:8: Duplicate words (script) found
/Users/fliter/video-tmp/kubernetes/test/e2e/storage/utils/ebs.go:49:1: Duplicate words (to) found
/Users/fliter/video-tmp/kubernetes/test/e2e/apps/statefulset.go:1665:1: Duplicate words (to) found
/Users/fliter/video-tmp/kubernetes/test/e2e/apimachinery/discovery.go:71:3: Duplicate words (resources) found
/Users/fliter/video-tmp/kubernetes/test/e2e/instrumentation/logging/utils/wait.go:75:1: Duplicate words (still) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:810:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:822:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:823:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:824:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:825:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:826:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:827:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:828:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:829:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:833:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:834:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:835:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:836:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:837:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:838:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:839:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:840:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/netpol/network_policy.go:841:4: Duplicate words (X) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/network_tiers.go:162:2: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/networking_perf.go:266:3: Duplicate words (three-node-ipv6-worker2) found
/Users/fliter/video-tmp/kubernetes/test/e2e/network/service.go:320:1: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/test/e2e/storage/testsuites/capacity.go:209:1: Duplicate words (when) found
/Users/fliter/video-tmp/kubernetes/test/e2e/windows/security_context.go:137:3: Duplicate words (the) found
/Users/fliter/video-tmp/kubernetes/test/e2e/windows/host_process.go:466:32: Duplicate words (create) found
/Users/fliter/video-tmp/kubernetes/test/images/regression-issue-74839/tcp.go:159:3: Duplicate words (IPv6) found
/Users/fliter/video-tmp/kubernetes/cluster/gce/gci/append_or_replace_prefixed_line_test.go:59:25: Duplicate words (helloworld) found
/Users/fliter/video-tmp/kubernetes/cmd/kubeadm/app/cmd/upgrade/plan_test.go:369:26: Duplicate words (v1.19.3) found
/Users/fliter/video-tmp/kubernetes/cmd/kubeadm/app/phases/controlplane/manifests_test.go:98:16: Duplicate words (KubeAPIServer) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/apps/validation/validation_test.go:1062:10: Duplicate words (update) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/validation/events_test.go:377:14: Duplicate words (zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/validation/events_test.go:569:14: Duplicate words (zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/validation/validation_test.go:4436:10: Duplicate words (dot) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/validation/validation_test.go:4458:10: Duplicate words (dot) found
/Users/fliter/video-tmp/kubernetes/pkg/apis/core/validation/validation_test.go:4480:10: Duplicate words (dot) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/controller_ref_manager_test.go:287:18: Duplicate words (uid) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/cronjob/utils_test.go:193:3: Duplicate words (way) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/cronjob/utils_test.go:203:3: Duplicate words (way) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/deployment/recreate_test.go:227:6: Duplicate words (pod) found
/Users/fliter/video-tmp/kubernetes/pkg/controller/podautoscaler/horizontal_test.go:3593:34: Duplicate words (with) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:84:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:90:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:96:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:102:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:108:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:196:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:202:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go:208:4: Duplicate words (per) found
/Users/fliter/video-tmp/kubernetes/pkg/kubelet/kuberuntime/logs/logs_test.go:356:18: Duplicate words (abcdefg) found
/Users/fliter/video-tmp/kubernetes/pkg/proxy/service_test.go:705:13: Duplicate words (service) found
/Users/fliter/video-tmp/kubernetes/pkg/proxy/iptables/proxier_test.go:3612:13: Duplicate words (service) found
/Users/fliter/video-tmp/kubernetes/pkg/proxy/ipvs/proxier_test.go:2639:13: Duplicate words (service) found
/Users/fliter/video-tmp/kubernetes/pkg/scheduler/schedule_one_test.go:685:12: Duplicate words (timeout) found
/Users/fliter/video-tmp/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity/filtering_test.go:1286:4: Duplicate words (pod) found
/Users/fliter/video-tmp/kubernetes/plugin/pkg/admission/resourcequota/admission_test.go:665:1: Duplicate words (that) found
/Users/fliter/video-tmp/kubernetes/test/e2e_node/topology_manager_test.go:838:25: Duplicate words (with) found
/Users/fliter/video-tmp/kubernetes/test/integration/job/job_test.go:166:11: Duplicate words (the) found

不能无脑改,需要甄别。。

go的benchmark检测出的:

1
2
3
4
5
/Users/fliter/fixgo/20000/benchmarks/garbage/nethttp.go:40:67: Duplicate words (req) found
/Users/fliter/fixgo/20000/benchmarks/garbage/nethttp.go:1878:13: Duplicate words (Header,nil,) found
/Users/fliter/fixgo/20000/benchmarks/garbage/nethttp.go:4701:43: Duplicate words (Handler,Header,t.idleConn) found
/Users/fliter/fixgo/20000/benchmarks/third_party/biogo-examples/igor/igor/cluster.go:63:2: Duplicate words (all) found
/Users/fliter/fixgo/20000/benchmarks/third_party/biogo-examples/igor/igor/cluster.go:72:2: Duplicate words (are) found

我自己实现一个:

看其核心代码:https://github.com/Abirdcfly/dupword/blob/main/dupword.go#L88

检测了两处,一个是注释中,一个是字符串常量中 是否存在重复的单词 (实践来看,重复的情况主要还是在注释中)

两者的获取方式,详见代码

代码在 shuang/ast_dupl_new

1
2
3




golang中如何从一个ast.File类型的变量,得到ast.BasicLit类型?


*ast.File 类型表示一个 Go 源代码文件,其中包含了该文件的语法树。而 *ast.BasicLit 类型表示一个字面值(literal)表达式,例如字符串、数字、布尔值等。

要从 *ast.File 类型的变量中获取 *ast.BasicLit 类型的变量,需要先遍历语法树,找到所有的 *ast.BasicLit 节点,并对其进行处理。可以使用 go/ast 包中的 ast.Inspect 函数和 ast.Node 接口来实现。

以下是一个示例代码,用于从 *ast.File 类型的变量中获取所有的 *ast.BasicLit 类型的变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import (
"go/ast"
"go/parser"
"go/token"
)

func main() {
// 解析源代码文件,得到语法树
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, "example.go", nil, parser.ParseComments)
if err != nil {
panic(err)
}

// 遍历语法树,并查找所有的 BasicLit 节点
var basicLits []*ast.BasicLit
ast.Inspect(node, func(n ast.Node) bool {
if n == nil {
return false
}
if lit, ok := n.(*ast.BasicLit); ok {
basicLits = append(basicLits, lit)
}
return true
})

// 处理 BasicLit 节点
for _, lit := range basicLits {
// 在这里进行处理
}
}

在这个示例中,我们首先使用 parser.ParseFile 函数将一个 Go 源代码文件解析为语法树,然后使用 ast.Inspect 函数遍历语法树,并查找所有的 *ast.BasicLit 节点。在遍历过程中,如果找到了一个 *ast.BasicLit 节点,就将其添加到一个切片中。最终,我们就可以通过遍历这个切片来处理所有的 *ast.BasicLit 节点了。


staticcheck


https://github.com/dominikh/go-tools


gci


上海一哥们写的。。但这玩意儿和goimports有啥区别?


gofmt和goimports

有什么区别?

gofmtgoimports 都是 Go 语言官方提供的工具,用于格式化 Go 代码。它们的主要区别在于:

  • gofmt 工具只会格式化代码,不会对导入包进行处理。它会将代码按照约定的格式进行排版,例如缩进、花括号的位置、行末注释等,以确保代码具有良好的可读性和一致性。gofmt 工具可以自动检测代码中的格式问题,并进行自动修复。
  • goimports 工具除了对代码进行格式化外,还会自动处理导入包。它会将代码中使用的导入包进行排序,并删除未使用的导入包。此外,goimports 工具还会自动添加缺失的导入包,并自动处理导入包的别名等问题。与 gofmt 工具一样,goimports 工具也可以自动检测代码中的格式问题,并进行自动修复。

因此,如果你只需要格式化代码,而不需要处理导入包,可以使用 gofmt 工具。如果需要自动处理导入包,建议使用 goimports 工具。在实际使用中,这两个工具通常会一起使用,例如在代码提交前通过 goimports 处理导入包,并通过 gofmt 格式化代码。

ta们是官方提供的吗?

是的,gofmtgoimports 工具都是由 Go 语言官方提供的工具,它们都随着 Go 语言的安装包一起发布,并被广泛地应用于 Go 语言的开发和维护中。

gofmt 工具是 Go 语言自带的代码格式化工具,它可以自动对符合 Go 语言规范的代码进行格式化,并且可以检测到代码中的一些格式问题,例如缩进、空格、换行等。使用 gofmt 工具可以保证代码具有良好的可读性和一致性。

goimports 工具是基于 gofmt 的代码格式化工具,它可以自动处理代码中的导入包,并自动添加、删除和排序导入包,以确保代码的导入包部分具有良好的可读性和一致性。和 gofmt 一样,goimports 也是由 Go 语言官方提供的工具。

由于这些工具都是由 Go 语言官方提供的,因此它们具有较高的可靠性和稳定性,并且被广泛地应用于 Go 语言的开发和维护中。

如何对整个项目的代码做goimports?

要对整个项目的代码进行 goimports 处理,可以使用以下命令:

1
goimports -w $(find . -type f -name '*.go' -not -path "./vendor/*")

这个命令会在当前目录下(包括子目录)查找所有扩展名为 .go 的文件,并对它们进行 goimports 处理。其中,-not -path "./vendor/*" 选项可以排除掉 ./vendor 目录下的文件,以避免对第三方库的代码进行处理。

-w 选项表示将更改写回到文件中。使用该选项时,goimports 会自动修改代码文件,并将修改后的代码写回到对应的文件中。因此,在运行该命令之前,请务必备份您的代码文件,以免意外修改导致代码丢失。

另外,如果您使用的是 Go 1.16 及以上版本,goimports 工具已经被整合到了 go fmt 命令中。因此,可以使用以下命令代替上面的命令:

1
go fmt ./...

该命令会对当前目录及其子目录下的所有源代码文件进行格式化和导入包处理。需要注意的是,该命令会将所有未使用的导入包都删除掉,因此在使用该命令之前,请确保您的代码中没有未使用的导入包。

这个更实用:

goimports -w $(find . -type f -name '*.go' -not -path "./testdata/*" -not -path "./vendor/*")


如何对整个项目的代码做gofmt ?


要对整个项目的代码进行 gofmt 处理,可以使用以下命令:

1
gofmt -w $(find . -type f -name '*.go' -not -path "./vendor/*")

这个命令会在当前目录下(包括子目录)查找所有扩展名为 .go 的文件,并对它们进行 gofmt 处理。其中,-not -path "./vendor/*" 选项可以排除掉 ./vendor 目录下的文件,以避免对第三方库的代码进行处理。

使用 -w 选项可以将更改写回到文件中。使用该选项时,gofmt 会自动修改代码文件,并将修改后的代码写回到对应的文件中。因此,在运行该命令之前,请务必备份您的代码文件,以免意外修改导致代码丢失。

如果您只想检查代码文件是否符合 Go 语言规范,而不修改它们,可以省略 -w 选项,如下所示:

1
gofmt $(find . -type f -name '*.go' -not -path "./vendor/*")

该命令会在终端输出未符合 Go 语言规范的代码片段,而不会修改代码文件。



20241014补记:

https://go-review.googlesource.com/c/benchmarks/+/619616

https://go-review.googlesource.com/c/mobile/+/619596

不能用 -s

gofmt -w -s 和 gofmt -w 有何区别?

gofmt 是 Go 语言中的一个工具,用于格式化 Go 源代码。它可以自动调整代码的缩进、空格、对齐等,以确保代码风格的一致性。


gofmt -wgofmt -w -s 的区别:

  1. gofmt -w

    • -w 选项表示将格式化后的代码直接写回文件,而不是将结果输出到终端。
    • 使用 gofmt -w 时,gofmt 会读取文件内容,格式化代码,并将结果直接替换原来的文件内容。
  2. gofmt -w -s

    • -s 选项是 gofmt简化模式(simplify mode)。它不仅会格式化代码,还会自动简化某些冗余的 Go 代码结构。
    • 使用 -s 时,gofmt 不仅会调整缩进和空格,还会尝试简化代码。例如,它会将类似 x = x[:] 这样的表达式简化为 x = x,或者将某些不必要的类型转换简化。

举个例子:

假设有如下 Go 代码:

1
2
var x = []int{0, 1, 2}
y := x[:]

使用 gofmt -w 后的代码:

代码会保持原样,只进行格式化调整(如果有需要的话)。在这种情况下,代码不会发生变化,因为它已经是格式化过的。

1
2
var x = []int{0, 1, 2}
y := x[:]

使用 gofmt -w -s 后的代码:

因为 gofmt -s 会简化代码,它会将 y := x[:] 简化为 y := x,因此输出将变为:

1
2
var x = []int{0, 1, 2}
y := x

总结:

  • gofmt -w:仅格式化代码,不对代码结构做简化。
  • gofmt -w -s:格式化代码的同时,尝试简化冗余的代码结构。

因此,gofmt -w -s 是一个更强大的选项,能够在保证代码格式整齐的同时,移除不必要的复杂性。




20240823补记:

修改了点代码 https://github.com/containerd/nerdctl/pull/3346

此处得知

还有个比golint-ci更严苛的lint,叫 go-critic

相关lint的功能和使用:

https://go-critic.com/trophies.html

https://go-critic.com/overview.html

这个部分是配置 Gocritic Linter 的检查项。Gocritic 是一个强大的 Go 语言静态代码分析工具,它提供了各种诊断、性能和编码风格检查。这个配置列出了 Gocritic 中被启用的检查项,它们的作用如下:

  1. Diagnostic(诊断性)检查:

    • appendAssign: 检查是否可以使用 += 操作符来代替 append()
    • argOrder: 检查函数参数的顺序是否合理。
    • badCond: 检查条件语句中的常见错误。
    • caseOrder: 检查 switch 语句中 case 的顺序是否合理。
    • codegenComment: 检查是否有自动生成的注释。
    • commentedOutCode: 检查是否有被注释掉的代码。
    • deprecatedComment: 检查是否使用了已弃用的注释。
    • dupArg: 检查函数调用中是否有重复的参数。
    • dupBranchBody: 检查 if-else 分支中是否有重复的代码。
    • dupCase: 检查 switch 语句中是否有重复的 case
    • dupSubExpr: 检查是否有重复的子表达式。
    • exitAfterDefer: 检查是否在 defer 之后直接调用 os.Exit()
    • flagDeref: 检查是否对 flag.Bool*() 函数的返回值进行了解引用。
    • flagName: 检查 flag 包中的标志名是否命名合理。
    • nilValReturn: 检查函数是否返回 nil 值。
    • offBy1: 检查是否存在 off-by-one 错误。
    • sloppyReassign: 检查是否有松散的变量重新赋值。
    • weakCond: 检查条件语句是否可能存在问题。
    • octalLiteral: 检查是否使用了八进制字面量。
  2. Performance(性能)检查:

    • appendCombine: 检查是否可以合并多个 append() 调用。
    • equalFold: 检查是否可以使用 strings.EqualFold() 来代替手动实现的大小写无关的字符串比较。
    • hugeParam: 检查函数参数是否过大。
    • indexAlloc: 检查是否可以使用预分配的切片来避免内存分配。
    • rangeExprCopy: 检查是否在 for 循环的表达式中复制了过大的对象。
    • rangeValCopy: 检查是否在 for 循环的迭代变量中复制了过大的对象。
  3. Style(编码风格)检查:

    • assignOp: 检查是否可以使用复合赋值运算符。
    • boolExprSimplify: 检查布尔表达式是否可以简化。
    • captLocal: 检查局部变量命名是否符合惯例。
    • commentFormatting: 检查注释的格式是否一致。
    • commentedOutImport: 检查是否有被注释掉的导入语句。
    • defaultCaseOrder: 检查 switch 语句中 default 语句的位置是否合理。
    • docStub: 检查是否存在缺失文档的公共标识符。
    • elseif: 建议使用 else {if ...} 而不是 else if ...
    • emptyFallthrough: 检查 switch 语句中是否有空的 fallthrough 语句。
    • emptyStringTest: 检查是否有冗余的空字符串测试。
    • hexLiteral: 检查是否使用了十六进制字面量。
    • ifElseChain: 检查是否可以将多个 if-else 语句合并。
    • methodExprCall: 检查是否可以使用方法表达式来代替方法调用。
    • regexpMust: 检查是否使用了 regexp.MustCompile() 来避免运行时错误。
    • singleCaseSwitch: 检查是否可以将单个 caseswitch 语句改写为 if 语句。
    • sloppyLen: 检查是否有不必要的 len() 调用。
    • stringXbytes: 检查是否有不必要的 []byte() 转换。
    • switchTrue: 建议使用 if 语句而不是 switch true
    • typeAssertChain: 检查是否可以合并多个类型断言。
    • typeSwitchVar: 检查 switch 语句中的类型开关变量是否命名合理。
    • underef: 检查是否可以取消对指针的解引用。
    • unlabelStmt: 检查是否有无用的标签。
    • unlambda: 检查是否可以将匿名函数改写为常规函数。
    • unslice: 检查是否可以省略切片操作。
    • valSwap: 检查是否可以使用解构赋值来交换两个变量的值。
    • wrapperFunc: 检查是否存在仅调用另一个函数的包装函数。
    • yodaStyleExpr: 检查是否使用了”Yoda 条件”(将常量放在左侧)。
  4. Opinionated(观点性)检查:

    • builtinShadow: 检查是否覆盖了内置标识符。
    • importShadow: 检查是否遮蔽了导入的包名。
    • initClause: 检查 for 循环的初始化语句是否合理。
    • nestingReduce: 检查是否可以减少代码嵌套的深度。
    • paramTypeCombine: 检查是否可以合并函数参数的类型声明。
    • ptrToRefParam: 检查是否可以将指针参数改为引用参数。
    • typeUnparen: 检查是否可以省略类型声明周围的括号。
    • unnamedResult: 检查是否应该为函数返回值命名。
    • unnecessaryBlock: 检查是否有不必要的代码块。

总的来说, Gocritic 提供了一个全面的代码检查套件,涵盖了各种常见的编码问题和最佳实践。启用这些检查有助于提高代码的质量、可读性和性能。


本地使用:

go install -v github.com/go-critic/go-critic/cmd/gocritic@latest

gocritic check ./...

这样可以跳过检测..但实际还是报出来了..


gocritic 工具禁用sloppyTypeAssert

gocritic 是一个 Go 语言的静态代码分析工具,它能够检测各种代码问题和潜在的改进点。sloppyTypeAssert 是 gocritic 中的一个规则(linter),用于检测可能不安全或不严格的类型断言。如果你想禁用这个规则,有几种方法可以做到。让我为你详细解释一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Example 1: Disabling for a specific line
func example1() {
var x interface{}
//nolint:gocritic
_ = x.(int)
}

// Example 2: Disabling for an entire function
//nolint:gocritic
func example2() {
var x interface{}
_ = x.(int)
// Other code...
}

// Example 3: Disabling a specific check for an entire file
//nolint:sloppyTypeAssert
package main

func example3() {
var x interface{}
_ = x.(int)
}

// .golangci.yml configuration:
/*
linters-settings:
gocritic:
disabled-checks:
- sloppyTypeAssert
*/

禁用 gocritic 的 sloppyTypeAssert 规则有以下几种方法:

  1. 在代码中使用注释:

    • 对于单行禁用:
      在需要禁用检查的行之前添加注释 //nolint:gocritic 或更具体的 //nolint:sloppyTypeAssert

    • 对于整个函数禁用:
      在函数定义之前添加注释 //nolint:gocritic//nolint:sloppyTypeAssert

    • 对于整个文件禁用:
      在文件顶部(package 声明之前)添加注释 //nolint:sloppyTypeAssert

  2. 使用配置文件:

    如果你使用 golangci-lint(它包含了 gocritic),你可以在 .golangci.yml 配置文件中禁用这个检查:

    1
    2
    3
    4
    linters-settings:
    gocritic:
    disabled-checks:
    - sloppyTypeAssert
  3. 命令行参数:

    如果你直接使用 gocritic 命令行工具,你可以使用 -disable 标志:

    1
    gocritic check -disable sloppyTypeAssert ./...

选择哪种方法取决于你的具体需求:

  • 如果你只想在特定的地方禁用这个检查,使用代码注释是最好的选择。
  • 如果你想在整个项目中禁用这个检查,使用配置文件是更好的选择。
  • 如果你只是临时禁用这个检查,使用命令行参数可能更方便。

记住,虽然禁用 linter 规则可以解决警告,但通常更好的做法是理解警告的原因并改进代码。sloppyTypeAssert 规则旨在防止不安全的类型断言,所以在禁用它之前,请确保你了解可能的风险。


如何禁用sloppyTypeAssert和singleCaseSwitch


要同时禁用 gocritic 的 sloppyTypeAssertsingleCaseSwitch 规则,你可以采用类似的方法。我会为你展示几种不同的方式来实现这一目标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Example 1: Disabling for specific lines
func example1() {
var x interface{}
//nolint:gocritic
_ = x.(int)

//nolint:gocritic
switch someValue {
case 1:
// Do something
}
}

// Example 2: Disabling for an entire function
//nolint:gocritic
func example2() {
var x interface{}
_ = x.(int)

switch someValue {
case 1:
// Do something
}
}

// Example 3: Disabling specific checks for an entire file
//nolint:sloppyTypeAssert,singleCaseSwitch
package main

func example3() {
var x interface{}
_ = x.(int)

switch someValue {
case 1:
// Do something
}
}

// .golangci.yml configuration:
/*
linters-settings:
gocritic:
disabled-checks:
- sloppyTypeAssert
- singleCaseSwitch
*/

现在,让我详细解释这些方法:

  1. 在代码中使用注释:

    a. 对于单行禁用:

    1
    2
    3
    4
    5
    6
    7
    8
    //nolint:gocritic
    _ = x.(int)

    //nolint:gocritic
    switch someValue {
    case 1:
    // Do something
    }

    或者更具体地:

    1
    2
    3
    4
    5
    6
    7
    8
    //nolint:sloppyTypeAssert
    _ = x.(int)

    //nolint:singleCaseSwitch
    switch someValue {
    case 1:
    // Do something
    }

    b. 对于整个函数禁用:

    1
    2
    3
    4
    //nolint:gocritic
    func example() {
    // Your function code here
    }

    c. 对于整个文件禁用:
    在文件顶部(package 声明之前)添加:

    1
    2
    //nolint:sloppyTypeAssert,singleCaseSwitch
    package main
  2. 使用配置文件:

    如果你使用 golangci-lint,你可以在 .golangci.yml 配置文件中禁用这些检查:

    1
    2
    3
    4
    5
    linters-settings:
    gocritic:
    disabled-checks:
    - sloppyTypeAssert
    - singleCaseSwitch
  3. 命令行参数:

    如果你直接使用 gocritic 命令行工具,你可以使用 -disable 标志:

    1
    gocritic check -disable sloppyTypeAssert,singleCaseSwitch ./...

选择最适合你的方法:

  • 使用代码注释适合于你只想在特定位置禁用这些规则的情况。
  • 使用配置文件是在整个项目中禁用这些规则的好方法。
  • 命令行参数适合临时禁用这些规则。

请记住,虽然禁用 linter 规则可以消除警告,但通常更好的做法是理解警告的原因并改进代码。sloppyTypeAssert 规则旨在防止不安全的类型断言,而 singleCaseSwitch 规则通常建议使用 if 语句替代只有一个 case 的 switch 语句。在禁用这些规则之前,请确保你了解可能的影响和风险。



我感觉挺好用的, 但确实噪音比较大,很多项应该禁用…

我用其中 appendAssign: append result not assigned to the same slice 定位到了go标准库 html/templete中的一处RSC于2021年提交的代码中的bug~

appendAssign 这个检测项很好用,很有可能是潜藏的bug… 但是有个大问题,就是对于 a : = append(b, "str")这种case也会报错, 其实是没有必要的…

我准备自己改一下,然后重新编译, 忽略这种情况

魔改go-critic




defaultCaseOrder


./watchtower/wtwire/init_test.go:95:2: defaultCaseOrder: consider to make default case as first or as last case

switch语句可以包含一个default分支,一般放到最后(可以在任何位置,建议在最后一个)。 default在没有case语句的值和变量值相等的时候执行

所以这个检测项其实可以禁用~不是啥大毛病

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
)

func main() {
today := "Wednesday"

switch today {
case "Monday":
fmt.Println("今天是星期一。")
case "Tuesday":
fmt.Println("今天是星期二。")
default:
fmt.Println("今天是节假日!不用上班")
case "Wednesday":
fmt.Println("今天是星期三,劳动日。")
}
}

今天是星期三,劳动日。




bad syntax for struct tag value 什么原因?哪个分析器报告的


–分割线–

是 go vet 在2018年 就有的~


“bad syntax for struct tag value” 错误通常出现在 Go 语言中,当你在结构体字段的标签(tag)中使用了不正确的语法时。Go 的结构体标签是以反引号包围的字符串,通常用于 JSON、XML 等编码的自定义设置。

常见原因

  1. 缺少反引号

    • 标签必须用反引号包围,例如:json:"fieldName"
  2. 不当的格式

    • 标签中可能包含了非法字符或不符合格式的内容。
  3. 多个标签的分隔符

    • 如果有多个标签,它们应该用空格分隔,而不是其他字符(例如,,)。

示例

错误示例

1
2
3
4
type Example struct {
Field1 string `json:"field1" xml:"field1"` // 正确
Field2 string json:"field2"` // 错误:缺少反引号
}

正确示例

1
2
3
4
type Example struct {
Field1 string `json:"field1" xml:"field1"` // 正确
Field2 string `json:"field2"` // 正确
}

哪个分析器报告的?

这个错误通常由 Go 的编译器(go buildgo vet)报告。它们会在编译时检查结构体标签的语法,并报告任何不符合规范的情况。

解决方法

检查所有的结构体标签,确保它们符合以下规则:

  • 使用反引号包围。
  • 标签的格式应正确,符合预期的键值对形式。
  • 多个标签之间用空格分隔。

修正这些问题后,重新编译你的代码,错误应该会消失。


call to time.Since is not deferred 什么意思?哪个分析器报告的

–分割线–

是 go vet 在2023年 增加的

以下是这段文本的翻译和解释:


defers 的描述

Package defers 定义了一个分析器(Analyzer),用于检查 defer 语句中的常见错误。

分析器 defers

defers: 报告 defer 语句中的常见错误。

分析器的功能

defers 分析器会在 defer 语句导致对 time.Since 的非延迟调用时报告诊断信息,因为经验表明,这几乎总是一个错误。

示例

例如,以下代码:

1
2
3
start := time.Now()
// ...
defer recordLatency(time.Since(start)) // 错误:对 time.Since 的调用不是延迟的

正确的写法

正确的代码应该是:

1
defer func() { recordLatency(time.Since(start)) }()

总结

这段文本说明了 defers 包的目的以及如何使用它来避免在 defer 语句中犯错,尤其是关于 time.Since 的使用。通过延迟调用的方式,可以确保在函数结束时正确记录时间。

–分割线结束–


“call to time.Since is not deferred” 的消息通常是指你在代码中调用了 time.Since 函数,但没有以 defer 语句来延迟执行。这种用法通常出现在需要测量函数执行时间的场景中。

什么是 time.Since

time.Since(start time.Time) 返回从 start 到当前时间的持续时间。它通常用于性能分析或调试,以确定某个操作耗时。

为什么要使用 defer

使用 defer 的好处是,你可以在函数结束时自动记录时间。这样可以确保无论函数如何退出(正常或异常),时间都会被记录。

示例

错误用法

1
2
3
4
5
func example() {
start := time.Now()
// 执行一些操作
time.Since(start) // 这行可能会导致警告
}

正确用法

1
2
3
4
5
6
7
8
9
func example() {
start := time.Now()
defer func() {
duration := time.Since(start)
fmt.Printf("Operation took %s\n", duration)
}()

// 执行一些操作
}

哪个分析器报告的?

这个消息通常是由 golintstaticcheck 等静态分析工具报告的。它们会分析你的代码并提示潜在的性能问题或不符合最佳实践的用法。

解决方法

要解决这个问题,可以使用 defer 语句来延迟对 time.Since 的调用,如上面的正确用法示例所示。这样可以确保你在函数结束时记录下操作的持续时间。



misuse of unbuffered os.Signal channel as argument to signal.Notify



“misuse of unbuffered os.Signal channel as argument to signal.Notify” 的意思是你传递给 signal.Notify 函数的 os.Signal 通道是一个无缓冲通道,这可能导致程序在没有接收者的情况下阻塞。

背景

在 Go 中,os.Signal 通道用于接收操作系统的信号(如中断信号)。signal.Notify 函数将信号发送到指定的通道。如果这个通道是无缓冲的,那么在没有任何 goroutine 从该通道中读取信号之前,发送信号的 goroutine 将会阻塞,从而导致程序的死锁。

解决方案

要解决这个问题,可以使用一个带缓冲区的通道,或者确保在使用 signal.Notify 之前有一个 goroutine 正在接收信号。

使用带缓冲区的通道

1
2
3
4
5
6
7
8
signalChan := make(chan os.Signal, 1) // 创建一个缓冲通道
signal.Notify(signalChan, os.Interrupt)

// 处理信号的 goroutine
go func() {
<-signalChan
fmt.Println("Received interrupt signal")
}()

确保有接收者

如果你希望使用无缓冲通道,可以确保在调用 signal.Notify 之前启动一个 goroutine 来接收信号:

1
2
3
4
5
6
7
8
9
10
signalChan := make(chan os.Signal)
signal.Notify(signalChan, os.Interrupt)

// 启动一个 goroutine 来接收信号
go func() {
for {
sig := <-signalChan
fmt.Println("Received signal:", sig)
}
}()

总结

  • 使用带缓冲的通道 是最简单的解决方案。
  • 确保有接收者 也可以解决此问题,但需要小心管理 goroutine 的生命周期。
    选择合适的方案可以避免程序的阻塞和死锁。


call has possible Printf formatting directive %某某


packages/network/tcpserver/disseminator.go:144:2: github.com/sirupsen/logrus.Debug call has possible Printf formatting directive %x




这个禁用gocritic检测的标记好像没起作用啊,还是:

1
2
./secp256k1fx/output_owners_test.go:146:17: dupArg: suspicious method call with the same argument and receiver
./secp256k1fx/output_owners_test.go:147:17: dupArg: suspicious method call with the same argument and receiver

go/src/cmd/internal/src/pos.go:413:46: don’t use Yoda conditions (ST1017)

“don’t use Yoda conditions (ST1017)” 是一个来自 Go 语言静态分析工具 staticcheck 的警告。这个警告的意思是建议避免使用一种特定的条件表达式写法,称为“Yoda 条件”。

什么是 Yoda 条件?

Yoda 条件是指在条件语句中,将常量放在表达式的左侧,而变量放在右侧。例如:

1
2
3
if 5 == x {
// do something
}

这种写法源于 Yoda(《星球大战》中的角色)的说话方式,常常把动词放在句子的前面。它的主要目的是防止在比较时意外地使用赋值运算符(=)代替比较运算符(==),因为在 C 语言等语言中,错误地写成 if (x = 5) 会导致编译错误,而 if (5 == x) 则不会。

Go 语言的推荐做法

在 Go 语言中,这种写法并不常见,且并不必要,因为 Go 的编译器会检测到赋值错误。因此,推荐的做法是将变量放在条件的左侧,如下所示:

1
2
3
if x == 5 {
// do something
}

总结

为了提高代码的可读性和一致性,建议遵循 Go 语言的最佳实践,避免使用 Yoda 条件。使用标准的比较形式(变量在左,常量在右)会使代码更易于理解。



tools/go/analysis/passes/findcall/findcall.go:57:17: unnecessary use of fmt.Sprintf (S1039)

搜索 unnecessary use of
搜索 doesn’t have side effects




JetBrains出的Qodana


https://qodana.cloud/

集成在了他们的ide里面






20241102

Go夜读 #41 golint 及 golangci-lint 的介绍和使用 【 Go 夜读 】 提到了360搞得这个

https://github.com/qax-os/goreporter

https://github.com/wgliang

https://goreporter.github.io/zh/index.html

https://github.com/goreporter

发现xuri当时在时提过代码

当时属于360,目前看是奇安信的


另一个可以在线分析的:

https://goreportcard.com/ 赞!!

https://github.com/gojp/goreportcard 是”go语言日本分社”搞的

https://github.com/creekorful/goreportcard-action


gci

20250417

gci

https://github.com/cosmos/cosmos-sdk/pull/24499

1
2
3
4
5
6
linting store/snapshots [2025-04-15T14:39:39+00:00]
197Error: store/snapshots/manager_test.go:265:1: File is not properly formatted (gci)
198func (m mockExtensionSnapshotter) SnapshotName() string { return "mock" }
199^
2001 issues:
201 gci: 1 什么原因?

这个错误信息表明您的Go文件有被gci检测到的格式问题。gci是一个专注于导入顺序和分组的Go代码格式化工具。

错误显示问题出现在文件store/snapshots/manager_test.go的第265行,但实际上错误很可能与导入语句的组织有关,而不是错误输出中显示的函数定义。

“File is not properly formatted (gci)”错误表明文件顶部的导入语句没有按照项目中配置的规则进行组织。

要修复这个问题,您需要:

  1. 在文件上运行gci来自动格式化导入语句
  2. 检查是否有缺失的导入或未使用的导入

您可以通过运行以下命令来修复它:

1
gci write store/snapshots/manager_test.go

或者如果您想修复项目中的所有文件:

1
gci write ./...

如果您尚未安装gci,可以使用以下命令安装:

1
go install github.com/daixiang0/gci@latest

没事就执行下 gci write ./...

看起来相当不错啊~