Skip to content

Commit f9d9176

Browse files
committed
feat: add the gosmopolitan linter
1 parent 271a55d commit f9d9176

16 files changed

+219
-0
lines changed

.golangci.reference.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,39 @@ linters-settings:
940940
# Default: "0600"
941941
G306: "0600"
942942

943+
gosmopolitan:
944+
# Allow and ignore `time.Local` usages.
945+
#
946+
# Default: false
947+
allow-time-local: true
948+
# List of fully qualified names in the `(full/pkg/path).name` form, to act
949+
# as "i18n escape hatches".
950+
#
951+
# String literals inside call-like expressions to, or struct literals of
952+
# those names, are exempt from the writing system check.
953+
#
954+
# Default: []
955+
escape-hatches:
956+
- '(github.com/nicksnyder/go-i18n/v2/i18n).Message'
957+
- '(example.com/your/project/i18n/markers).Raw'
958+
- '(example.com/your/project/i18n/markers).OK'
959+
- '(example.com/your/project/i18n/markers).TODO'
960+
- '(command-line-arguments).Simple'
961+
# Ignore test files.
962+
#
963+
# Default: true
964+
ignore-tests: false
965+
# List of Unicode scripts to watch for any usage in string literals.
966+
# If empty the default of ["Han"] will be used.
967+
#
968+
# Default: ["Han"]
969+
watch-for-scripts:
970+
- Devanagari
971+
- Han
972+
- Hangul
973+
- Hiragana
974+
- Katakana
975+
943976
govet:
944977
# Report about shadowed variables.
945978
# Default: false
@@ -2023,6 +2056,7 @@ linters:
20232056
- goprintffuncname
20242057
- gosec
20252058
- gosimple
2059+
- gosmopolitan
20262060
- govet
20272061
- grouper
20282062
- ifshort
@@ -2131,6 +2165,7 @@ linters:
21312165
- goprintffuncname
21322166
- gosec
21332167
- gosimple
2168+
- gosmopolitan
21342169
- govet
21352170
- grouper
21362171
- ifshort

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ require (
105105
github.com/ultraware/whitespace v0.0.5
106106
github.com/uudashr/gocognit v1.0.6
107107
github.com/valyala/quicktemplate v1.7.0
108+
github.com/xen0n/gosmopolitan v1.1.1
108109
github.com/yagipy/maintidx v1.0.0
109110
github.com/yeya24/promlinter v0.2.0
110111
gitlab.com/bosi/decorder v0.2.3

go.sum

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/linters_settings.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ var defaultLintersSettings = LintersSettings{
6161
Gosec: GoSecSettings{
6262
Concurrency: runtime.NumCPU(),
6363
},
64+
Gosmopolitan: GosmopolitanSettings{
65+
AllowTimeLocal: false,
66+
EscapeHatches: []string{},
67+
IgnoreTests: true,
68+
WatchForScripts: []string{"Han"},
69+
},
6470
Ifshort: IfshortSettings{
6571
MaxDeclLines: 1,
6672
MaxDeclChars: 30,
@@ -167,6 +173,7 @@ type LintersSettings struct {
167173
Gomodguard GoModGuardSettings
168174
Gosec GoSecSettings
169175
Gosimple StaticCheckSettings
176+
Gosmopolitan GosmopolitanSettings
170177
Govet GovetSettings
171178
Grouper GrouperSettings
172179
Ifshort IfshortSettings
@@ -446,6 +453,13 @@ type GoSecSettings struct {
446453
Concurrency int `mapstructure:"concurrency"`
447454
}
448455

456+
type GosmopolitanSettings struct {
457+
AllowTimeLocal bool `mapstructure:"allow-time-local"`
458+
EscapeHatches []string `mapstructure:"escape-hatches"`
459+
IgnoreTests bool `mapstructure:"ignore-tests"`
460+
WatchForScripts []string `mapstructure:"watch-for-scripts"`
461+
}
462+
449463
type GovetSettings struct {
450464
Go string `mapstructure:"-"`
451465
CheckShadowing bool `mapstructure:"check-shadowing"`

pkg/golinters/gosmopolitan.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package golinters
2+
3+
import (
4+
"strings"
5+
6+
"github.com/xen0n/gosmopolitan"
7+
"golang.org/x/tools/go/analysis"
8+
9+
"github.com/golangci/golangci-lint/pkg/config"
10+
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
11+
)
12+
13+
func NewGosmopolitan(s *config.GosmopolitanSettings) *goanalysis.Linter {
14+
a := gosmopolitan.NewAnalyzer()
15+
16+
cfgMap := map[string]map[string]interface{}{}
17+
if s != nil {
18+
cfgMap[a.Name] = map[string]interface{}{
19+
"allowtimelocal": s.AllowTimeLocal,
20+
"escapehatches": strings.Join(s.EscapeHatches, ","),
21+
"lookattests": !s.IgnoreTests,
22+
"watchforscripts": strings.Join(s.WatchForScripts, ","),
23+
}
24+
}
25+
26+
return goanalysis.NewLinter(
27+
a.Name,
28+
a.Doc,
29+
[]*analysis.Analyzer{a},
30+
cfgMap,
31+
).WithLoadMode(goanalysis.LoadModeTypesInfo)
32+
}

pkg/lint/lintersdb/manager.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
135135
gomodguardCfg *config.GoModGuardSettings
136136
gosecCfg *config.GoSecSettings
137137
gosimpleCfg *config.StaticCheckSettings
138+
gosmopolitanCfg *config.GosmopolitanSettings
138139
govetCfg *config.GovetSettings
139140
grouperCfg *config.GrouperSettings
140141
ifshortCfg *config.IfshortSettings
@@ -212,6 +213,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
212213
gomodguardCfg = &m.cfg.LintersSettings.Gomodguard
213214
gosecCfg = &m.cfg.LintersSettings.Gosec
214215
gosimpleCfg = &m.cfg.LintersSettings.Gosimple
216+
gosmopolitanCfg = &m.cfg.LintersSettings.Gosmopolitan
215217
govetCfg = &m.cfg.LintersSettings.Govet
216218
grouperCfg = &m.cfg.LintersSettings.Grouper
217219
ifshortCfg = &m.cfg.LintersSettings.Ifshort
@@ -550,6 +552,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
550552
WithAlternativeNames(megacheckName).
551553
WithURL("https://github.com/dominikh/go-tools/tree/master/simple"),
552554

555+
linter.NewConfig(golinters.NewGosmopolitan(gosmopolitanCfg)).
556+
WithSince("v1.51.0").
557+
WithLoadForGoAnalysis().
558+
WithPresets(linter.PresetBugs).
559+
WithURL("https://github.com/xen0n/gosmopolitan"),
560+
553561
linter.NewConfig(golinters.NewGovet(govetCfg)).
554562
WithSince("v1.0.0").
555563
WithLoadForGoAnalysis().
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
linters-settings:
2+
gosmopolitan:
3+
allow-time-local: true
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
linters-settings:
2+
gosmopolitan:
3+
ignore-tests: false
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
linters-settings:
2+
gosmopolitan:
3+
escape-hatches:
4+
- '(command-line-arguments).A'
5+
- '(command-line-arguments).B'
6+
- '(command-line-arguments).C'
7+
- '(command-line-arguments).D'
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
linters-settings:
2+
gosmopolitan:
3+
watch-for-scripts:
4+
- Hiragana
5+
- Katakana
6+
- Latin
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//golangcitest:args -Egosmopolitan
2+
//golangcitest:config_path testdata/configs/gosmopolitan_allow_time_local.yml
3+
//golangcitest:expected_exitcode 0
4+
package testdata
5+
6+
import (
7+
"time"
8+
)
9+
10+
func main() {
11+
_ = time.Local
12+
}

test/testdata/gosmopolitan_default.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//golangcitest:args -Egosmopolitan
2+
package testdata
3+
4+
import (
5+
"fmt"
6+
"time"
7+
)
8+
9+
type col struct {
10+
// struct tag should not get reported
11+
Foo string `gorm:"column:bar;not null;comment:'不应该报告这一行'"`
12+
}
13+
14+
func main() {
15+
fmt.Println("hello world")
16+
fmt.Println("你好,世界") // want `string literal contains rune in Han script`
17+
fmt.Println("こんにちは、セカイ")
18+
19+
_ = col{Foo: "hello"}
20+
_ = col{Foo: "你好"} // want `string literal contains rune in Han script`
21+
22+
x := time.Local // want `usage of time.Local`
23+
_ = time.Now().In(x)
24+
_ = time.Date(2023, 1, 2, 3, 4, 5, 678901234, time.Local) // want `usage of time.Local`
25+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//golangcitest:args -Egosmopolitan
2+
//golangcitest:config_path testdata/configs/gosmopolitan_dont_ignore_tests.yml
3+
package testdata
4+
5+
import (
6+
"time"
7+
)
8+
9+
func main() {
10+
_ = "开启检查测试文件" // want `string literal contains rune in Han script`
11+
_ = time.Local // want `usage of time.Local`
12+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//golangcitest:args -Egosmopolitan
2+
//golangcitest:config_path testdata/configs/gosmopolitan_escape_hatches.yml
3+
package testdata
4+
5+
type A string
6+
type B = string
7+
type C struct {
8+
foo string
9+
Bar string
10+
}
11+
12+
func D(fmt string) string {
13+
return fmt
14+
}
15+
16+
type X struct {
17+
baz string
18+
}
19+
20+
func main() {
21+
_ = A("测试")
22+
_ = string(A(string("测试")))
23+
_ = B("测试")
24+
_ = C{
25+
foo: "测试",
26+
Bar: "测试",
27+
}
28+
_ = D("测试")
29+
30+
_ = &X{
31+
baz: "测试", // want `string literal contains rune in Han script`
32+
}
33+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//golangcitest:args -Egosmopolitan
2+
//golangcitest:expected_exitcode 0
3+
package testdata
4+
5+
import (
6+
"time"
7+
)
8+
9+
func main() {
10+
_ = "默认不检查测试文件"
11+
_ = time.Local
12+
}

test/testdata/gosmopolitan_scripts.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//golangcitest:args -Egosmopolitan
2+
//golangcitest:config_path testdata/configs/gosmopolitan_scripts.yml
3+
package testdata
4+
5+
import (
6+
"fmt"
7+
)
8+
9+
func main() {
10+
fmt.Println("hello world") // want `string literal contains rune in Latin script`
11+
fmt.Println("should not report this line") //nolint:gosmopolitan
12+
fmt.Println("你好,世界")
13+
fmt.Println("こんにちは、セカイ") // want `string literal contains rune in Hiragana script`
14+
}

0 commit comments

Comments
 (0)