feat: add the gosmopolitan linter (#3458)
This commit is contained in:
parent
b29a4f6dc0
commit
553d7df585
@ -948,6 +948,37 @@ linters-settings:
|
|||||||
# Default: "0600"
|
# Default: "0600"
|
||||||
G306: "0600"
|
G306: "0600"
|
||||||
|
|
||||||
|
gosmopolitan:
|
||||||
|
# Allow and ignore `time.Local` usages.
|
||||||
|
#
|
||||||
|
# Default: false
|
||||||
|
allow-time-local: true
|
||||||
|
# List of fully qualified names in the `full/pkg/path.name` form, to act as "i18n escape hatches".
|
||||||
|
# String literals inside call-like expressions to, or struct literals of those names,
|
||||||
|
# are exempt from the writing system check.
|
||||||
|
#
|
||||||
|
# Default: []
|
||||||
|
escape-hatches:
|
||||||
|
- 'github.com/nicksnyder/go-i18n/v2/i18n.Message'
|
||||||
|
- 'example.com/your/project/i18n/markers.Raw'
|
||||||
|
- 'example.com/your/project/i18n/markers.OK'
|
||||||
|
- 'example.com/your/project/i18n/markers.TODO'
|
||||||
|
- 'command-line-arguments.Simple'
|
||||||
|
# Ignore test files.
|
||||||
|
#
|
||||||
|
# Default: true
|
||||||
|
ignore-tests: false
|
||||||
|
# List of Unicode scripts to watch for any usage in string literals.
|
||||||
|
# https://pkg.go.dev/unicode#pkg-variables
|
||||||
|
#
|
||||||
|
# Default: ["Han"]
|
||||||
|
watch-for-scripts:
|
||||||
|
- Devanagari
|
||||||
|
- Han
|
||||||
|
- Hangul
|
||||||
|
- Hiragana
|
||||||
|
- Katakana
|
||||||
|
|
||||||
govet:
|
govet:
|
||||||
# Report about shadowed variables.
|
# Report about shadowed variables.
|
||||||
# Default: false
|
# Default: false
|
||||||
@ -2049,6 +2080,7 @@ linters:
|
|||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
- gosec
|
- gosec
|
||||||
- gosimple
|
- gosimple
|
||||||
|
- gosmopolitan
|
||||||
- govet
|
- govet
|
||||||
- grouper
|
- grouper
|
||||||
- ifshort
|
- ifshort
|
||||||
@ -2159,6 +2191,7 @@ linters:
|
|||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
- gosec
|
- gosec
|
||||||
- gosimple
|
- gosimple
|
||||||
|
- gosmopolitan
|
||||||
- govet
|
- govet
|
||||||
- grouper
|
- grouper
|
||||||
- ifshort
|
- ifshort
|
||||||
|
1
go.mod
1
go.mod
@ -106,6 +106,7 @@ require (
|
|||||||
github.com/ultraware/whitespace v0.0.5
|
github.com/ultraware/whitespace v0.0.5
|
||||||
github.com/uudashr/gocognit v1.0.6
|
github.com/uudashr/gocognit v1.0.6
|
||||||
github.com/valyala/quicktemplate v1.7.0
|
github.com/valyala/quicktemplate v1.7.0
|
||||||
|
github.com/xen0n/gosmopolitan v1.2.1
|
||||||
github.com/yagipy/maintidx v1.0.0
|
github.com/yagipy/maintidx v1.0.0
|
||||||
github.com/yeya24/promlinter v0.2.0
|
github.com/yeya24/promlinter v0.2.0
|
||||||
gitlab.com/bosi/decorder v0.2.3
|
gitlab.com/bosi/decorder v0.2.3
|
||||||
|
2
go.sum
generated
2
go.sum
generated
@ -548,6 +548,8 @@ github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD
|
|||||||
github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
|
github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
|
||||||
github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
|
github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
|
github.com/xen0n/gosmopolitan v1.2.1 h1:3pttnTuFumELBRSh+KQs1zcz4fN6Zy7aB0xlnQSn1Iw=
|
||||||
|
github.com/xen0n/gosmopolitan v1.2.1/go.mod h1:JsHq/Brs1o050OOdmzHeOr0N7OtlnKRAGAsElF8xBQA=
|
||||||
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
|
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
|
||||||
github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
|
github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
|
||||||
github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o=
|
github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o=
|
||||||
|
@ -61,6 +61,12 @@ var defaultLintersSettings = LintersSettings{
|
|||||||
Gosec: GoSecSettings{
|
Gosec: GoSecSettings{
|
||||||
Concurrency: runtime.NumCPU(),
|
Concurrency: runtime.NumCPU(),
|
||||||
},
|
},
|
||||||
|
Gosmopolitan: GosmopolitanSettings{
|
||||||
|
AllowTimeLocal: false,
|
||||||
|
EscapeHatches: []string{},
|
||||||
|
IgnoreTests: true,
|
||||||
|
WatchForScripts: []string{"Han"},
|
||||||
|
},
|
||||||
Ifshort: IfshortSettings{
|
Ifshort: IfshortSettings{
|
||||||
MaxDeclLines: 1,
|
MaxDeclLines: 1,
|
||||||
MaxDeclChars: 30,
|
MaxDeclChars: 30,
|
||||||
@ -167,6 +173,7 @@ type LintersSettings struct {
|
|||||||
Gomodguard GoModGuardSettings
|
Gomodguard GoModGuardSettings
|
||||||
Gosec GoSecSettings
|
Gosec GoSecSettings
|
||||||
Gosimple StaticCheckSettings
|
Gosimple StaticCheckSettings
|
||||||
|
Gosmopolitan GosmopolitanSettings
|
||||||
Govet GovetSettings
|
Govet GovetSettings
|
||||||
Grouper GrouperSettings
|
Grouper GrouperSettings
|
||||||
Ifshort IfshortSettings
|
Ifshort IfshortSettings
|
||||||
@ -449,6 +456,13 @@ type GoSecSettings struct {
|
|||||||
Concurrency int `mapstructure:"concurrency"`
|
Concurrency int `mapstructure:"concurrency"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GosmopolitanSettings struct {
|
||||||
|
AllowTimeLocal bool `mapstructure:"allow-time-local"`
|
||||||
|
EscapeHatches []string `mapstructure:"escape-hatches"`
|
||||||
|
IgnoreTests bool `mapstructure:"ignore-tests"`
|
||||||
|
WatchForScripts []string `mapstructure:"watch-for-scripts"`
|
||||||
|
}
|
||||||
|
|
||||||
type GovetSettings struct {
|
type GovetSettings struct {
|
||||||
Go string `mapstructure:"-"`
|
Go string `mapstructure:"-"`
|
||||||
CheckShadowing bool `mapstructure:"check-shadowing"`
|
CheckShadowing bool `mapstructure:"check-shadowing"`
|
||||||
|
32
pkg/golinters/gosmopolitan.go
Normal file
32
pkg/golinters/gosmopolitan.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package golinters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/xen0n/gosmopolitan"
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewGosmopolitan(s *config.GosmopolitanSettings) *goanalysis.Linter {
|
||||||
|
a := gosmopolitan.NewAnalyzer()
|
||||||
|
|
||||||
|
cfgMap := map[string]map[string]interface{}{}
|
||||||
|
if s != nil {
|
||||||
|
cfgMap[a.Name] = map[string]interface{}{
|
||||||
|
"allowtimelocal": s.AllowTimeLocal,
|
||||||
|
"escapehatches": strings.Join(s.EscapeHatches, ","),
|
||||||
|
"lookattests": !s.IgnoreTests,
|
||||||
|
"watchforscripts": strings.Join(s.WatchForScripts, ","),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return goanalysis.NewLinter(
|
||||||
|
a.Name,
|
||||||
|
a.Doc,
|
||||||
|
[]*analysis.Analyzer{a},
|
||||||
|
cfgMap,
|
||||||
|
).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||||
|
}
|
@ -135,6 +135,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
gomodguardCfg *config.GoModGuardSettings
|
gomodguardCfg *config.GoModGuardSettings
|
||||||
gosecCfg *config.GoSecSettings
|
gosecCfg *config.GoSecSettings
|
||||||
gosimpleCfg *config.StaticCheckSettings
|
gosimpleCfg *config.StaticCheckSettings
|
||||||
|
gosmopolitanCfg *config.GosmopolitanSettings
|
||||||
govetCfg *config.GovetSettings
|
govetCfg *config.GovetSettings
|
||||||
grouperCfg *config.GrouperSettings
|
grouperCfg *config.GrouperSettings
|
||||||
ifshortCfg *config.IfshortSettings
|
ifshortCfg *config.IfshortSettings
|
||||||
@ -213,6 +214,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
gomodguardCfg = &m.cfg.LintersSettings.Gomodguard
|
gomodguardCfg = &m.cfg.LintersSettings.Gomodguard
|
||||||
gosecCfg = &m.cfg.LintersSettings.Gosec
|
gosecCfg = &m.cfg.LintersSettings.Gosec
|
||||||
gosimpleCfg = &m.cfg.LintersSettings.Gosimple
|
gosimpleCfg = &m.cfg.LintersSettings.Gosimple
|
||||||
|
gosmopolitanCfg = &m.cfg.LintersSettings.Gosmopolitan
|
||||||
govetCfg = &m.cfg.LintersSettings.Govet
|
govetCfg = &m.cfg.LintersSettings.Govet
|
||||||
grouperCfg = &m.cfg.LintersSettings.Grouper
|
grouperCfg = &m.cfg.LintersSettings.Grouper
|
||||||
ifshortCfg = &m.cfg.LintersSettings.Ifshort
|
ifshortCfg = &m.cfg.LintersSettings.Ifshort
|
||||||
@ -558,6 +560,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
WithAlternativeNames(megacheckName).
|
WithAlternativeNames(megacheckName).
|
||||||
WithURL("https://github.com/dominikh/go-tools/tree/master/simple"),
|
WithURL("https://github.com/dominikh/go-tools/tree/master/simple"),
|
||||||
|
|
||||||
|
linter.NewConfig(golinters.NewGosmopolitan(gosmopolitanCfg)).
|
||||||
|
WithSince("v1.53.0").
|
||||||
|
WithLoadForGoAnalysis().
|
||||||
|
WithPresets(linter.PresetBugs).
|
||||||
|
WithURL("https://github.com/xen0n/gosmopolitan"),
|
||||||
|
|
||||||
linter.NewConfig(golinters.NewGovet(govetCfg)).
|
linter.NewConfig(golinters.NewGovet(govetCfg)).
|
||||||
WithSince("v1.0.0").
|
WithSince("v1.0.0").
|
||||||
WithLoadForGoAnalysis().
|
WithLoadForGoAnalysis().
|
||||||
|
3
test/testdata/configs/gosmopolitan_allow_time_local.yml
vendored
Normal file
3
test/testdata/configs/gosmopolitan_allow_time_local.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
linters-settings:
|
||||||
|
gosmopolitan:
|
||||||
|
allow-time-local: true
|
3
test/testdata/configs/gosmopolitan_dont_ignore_tests.yml
vendored
Normal file
3
test/testdata/configs/gosmopolitan_dont_ignore_tests.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
linters-settings:
|
||||||
|
gosmopolitan:
|
||||||
|
ignore-tests: false
|
8
test/testdata/configs/gosmopolitan_escape_hatches.yml
vendored
Normal file
8
test/testdata/configs/gosmopolitan_escape_hatches.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
linters-settings:
|
||||||
|
gosmopolitan:
|
||||||
|
escape-hatches:
|
||||||
|
- 'command-line-arguments.A'
|
||||||
|
- 'command-line-arguments.B'
|
||||||
|
- 'command-line-arguments.C'
|
||||||
|
- 'command-line-arguments.D'
|
||||||
|
- 'fmt.Println'
|
6
test/testdata/configs/gosmopolitan_scripts.yml
vendored
Normal file
6
test/testdata/configs/gosmopolitan_scripts.yml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
linters-settings:
|
||||||
|
gosmopolitan:
|
||||||
|
watch-for-scripts:
|
||||||
|
- Hiragana
|
||||||
|
- Katakana
|
||||||
|
- Latin
|
25
test/testdata/gosmopolitan.go
vendored
Normal file
25
test/testdata/gosmopolitan.go
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//golangcitest:args -Egosmopolitan
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type col struct {
|
||||||
|
// struct tag should not get reported
|
||||||
|
Foo string `gorm:"column:bar;not null;comment:'不应该报告这一行'"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("hello world")
|
||||||
|
fmt.Println("你好,世界") // want `string literal contains rune in Han script`
|
||||||
|
fmt.Println("こんにちは、セカイ")
|
||||||
|
|
||||||
|
_ = col{Foo: "hello"}
|
||||||
|
_ = col{Foo: "你好"} // want `string literal contains rune in Han script`
|
||||||
|
|
||||||
|
x := time.Local // want `usage of time.Local`
|
||||||
|
_ = time.Now().In(x)
|
||||||
|
_ = time.Date(2023, 1, 2, 3, 4, 5, 678901234, time.Local) // want `usage of time.Local`
|
||||||
|
}
|
12
test/testdata/gosmopolitan_allow_time_local.go
vendored
Normal file
12
test/testdata/gosmopolitan_allow_time_local.go
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//golangcitest:args -Egosmopolitan
|
||||||
|
//golangcitest:config_path testdata/configs/gosmopolitan_allow_time_local.yml
|
||||||
|
//golangcitest:expected_exitcode 0
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = time.Local
|
||||||
|
}
|
12
test/testdata/gosmopolitan_dont_ignore_test.go
vendored
Normal file
12
test/testdata/gosmopolitan_dont_ignore_test.go
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//golangcitest:args -Egosmopolitan
|
||||||
|
//golangcitest:config_path testdata/configs/gosmopolitan_dont_ignore_tests.yml
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = "开启检查测试文件" // want `string literal contains rune in Han script`
|
||||||
|
_ = time.Local // want `usage of time.Local`
|
||||||
|
}
|
38
test/testdata/gosmopolitan_escape_hatches.go
vendored
Normal file
38
test/testdata/gosmopolitan_escape_hatches.go
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//golangcitest:args -Egosmopolitan
|
||||||
|
//golangcitest:config_path testdata/configs/gosmopolitan_escape_hatches.yml
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
myAlias "fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type A string
|
||||||
|
type B = string
|
||||||
|
type C struct {
|
||||||
|
foo string
|
||||||
|
Bar string
|
||||||
|
}
|
||||||
|
|
||||||
|
func D(fmt string) string {
|
||||||
|
myAlias.Println(fmt, "测试")
|
||||||
|
return myAlias.Sprintf("%s 测试", fmt) // want `string literal contains rune in Han script`
|
||||||
|
}
|
||||||
|
|
||||||
|
type X struct {
|
||||||
|
baz string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = A("测试")
|
||||||
|
_ = string(A(string("测试")))
|
||||||
|
_ = B("测试")
|
||||||
|
_ = C{
|
||||||
|
foo: "测试",
|
||||||
|
Bar: "测试",
|
||||||
|
}
|
||||||
|
_ = D("测试")
|
||||||
|
|
||||||
|
_ = &X{
|
||||||
|
baz: "测试", // want `string literal contains rune in Han script`
|
||||||
|
}
|
||||||
|
}
|
12
test/testdata/gosmopolitan_ignore_test.go
vendored
Normal file
12
test/testdata/gosmopolitan_ignore_test.go
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//golangcitest:args -Egosmopolitan
|
||||||
|
//golangcitest:expected_exitcode 0
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_ = "默认不检查测试文件"
|
||||||
|
_ = time.Local
|
||||||
|
}
|
14
test/testdata/gosmopolitan_scripts.go
vendored
Normal file
14
test/testdata/gosmopolitan_scripts.go
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//golangcitest:args -Egosmopolitan
|
||||||
|
//golangcitest:config_path testdata/configs/gosmopolitan_scripts.yml
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("hello world") // want `string literal contains rune in Latin script`
|
||||||
|
fmt.Println("should not report this line") //nolint:gosmopolitan
|
||||||
|
fmt.Println("你好,世界")
|
||||||
|
fmt.Println("こんにちは、セカイ") // want `string literal contains rune in Hiragana script`
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user