diff --git a/config/config.go b/config/config.go index 1c47f699f..29a57a45a 100644 --- a/config/config.go +++ b/config/config.go @@ -122,6 +122,9 @@ func (cfg Config) Merge(ocfg Config) Config { if ocfg.Initialisms != nil { cfg.Initialisms = mergeLists(cfg.Initialisms, ocfg.Initialisms) } + if ocfg.ProperNouns != nil { + cfg.ProperNouns = mergeLists(cfg.ProperNouns, ocfg.ProperNouns) + } if ocfg.DotImportWhitelist != nil { cfg.DotImportWhitelist = mergeLists(cfg.DotImportWhitelist, ocfg.DotImportWhitelist) } @@ -141,6 +144,7 @@ type Config struct { Checks []string `toml:"checks"` Initialisms []string `toml:"initialisms"` + ProperNouns []string `toml:"proper_nouns"` DotImportWhitelist []string `toml:"dot_import_whitelist"` HTTPStatusCodeWhitelist []string `toml:"http_status_code_whitelist"` } @@ -150,6 +154,7 @@ func (c Config) String() string { fmt.Fprintf(buf, "Checks: %#v\n", c.Checks) fmt.Fprintf(buf, "Initialisms: %#v\n", c.Initialisms) + fmt.Fprintf(buf, "ProperNouns: %#v\n", c.ProperNouns) fmt.Fprintf(buf, "DotImportWhitelist: %#v\n", c.DotImportWhitelist) fmt.Fprintf(buf, "HTTPStatusCodeWhitelist: %#v", c.HTTPStatusCodeWhitelist) @@ -173,6 +178,14 @@ var DefaultConfig = Config{ "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS", }, + ProperNouns: []string{ + "Amazon", "Android", "Ansible", "Azure", "Cloudflare", + "Consul", "Docker", "Elasticsearch", "Envoy", "Etcd", + "Grafana", "Heroku", "Istio", "Jenkins", "Jira", + "Kafka", "Kibana", "Kubernetes", "Linux", "Nginx", + "Nomad", "Postgres", "Prometheus", "Redis", "Terraform", + "Travis", "Vault", "Windows", + }, DotImportWhitelist: []string{ "simd/archsimd", "github.com/mmcloughlin/avo/build", @@ -271,6 +284,7 @@ func Load(dir string) (Config, error) { conf.Checks = normalizeList(conf.Checks) conf.Initialisms = normalizeList(conf.Initialisms) + conf.ProperNouns = normalizeList(conf.ProperNouns) conf.DotImportWhitelist = normalizeList(conf.DotImportWhitelist) conf.HTTPStatusCodeWhitelist = normalizeList(conf.HTTPStatusCodeWhitelist) diff --git a/config/example.conf b/config/example.conf index acc9d69e6..ef73f2cda 100644 --- a/config/example.conf +++ b/config/example.conf @@ -6,6 +6,12 @@ initialisms = ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"] +proper_nouns = ["Amazon", "Android", "Ansible", "Azure", "Cloudflare", + "Consul", "Docker", "Elasticsearch", "Envoy", "Etcd", + "Grafana", "Heroku", "Istio", "Jenkins", "Jira", + "Kafka", "Kibana", "Kubernetes", "Linux", "Nginx", + "Nomad", "Postgres", "Prometheus", "Redis", "Terraform", + "Travis", "Vault", "Windows"] dot_import_whitelist = [ "simd/archsimd", "github.com/mmcloughlin/avo/build", diff --git a/stylecheck/st1005/st1005.go b/stylecheck/st1005/st1005.go index 477c0a118..5c51cd89d 100644 --- a/stylecheck/st1005/st1005.go +++ b/stylecheck/st1005/st1005.go @@ -9,6 +9,7 @@ import ( "honnef.co/go/tools/analysis/code" "honnef.co/go/tools/analysis/lint" "honnef.co/go/tools/analysis/report" + "honnef.co/go/tools/config" "honnef.co/go/tools/go/ir" "honnef.co/go/tools/go/ir/irutil" "honnef.co/go/tools/internal/passes/buildir" @@ -20,7 +21,7 @@ var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ Analyzer: &analysis.Analyzer{ Name: "ST1005", Run: run, - Requires: []*analysis.Analyzer{buildir.Analyzer}, + Requires: []*analysis.Analyzer{buildir.Analyzer, config.Analyzer}, }, Doc: &lint.RawDocumentation{ Title: `Incorrectly formatted error string`, @@ -34,8 +35,12 @@ Quoting Go Code Review Comments: > usually printed following other context. That is, use > \'fmt.Errorf("something bad")\' not \'fmt.Errorf("Something bad")\', so > that \'log.Printf("Reading %s: %v", filename, err)\' formats without a -> spurious capital letter mid-message.`, +> spurious capital letter mid-message. + +The set of proper nouns that are allowed to start an error string can be +configured with the proper_nouns option.`, Since: "2019.1", + Options: []string{"proper_nouns"}, MergeIf: lint.MergeIfAny, }, }) @@ -43,6 +48,12 @@ Quoting Go Code Review Comments: var Analyzer = SCAnalyzer.Analyzer func run(pass *analysis.Pass) (any, error) { + pn := config.For(pass).ProperNouns + properNouns := make(map[string]bool, len(pn)) + for _, word := range pn { + properNouns[word] = true + } + objNames := map[*ir.Package]map[string]bool{} irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg objNames[irpkg] = map[string]bool{} @@ -115,6 +126,10 @@ func run(pass *analysis.Pass) (any, error) { // Word is probably the name of a function or type in this package continue } + if properNouns[word] { + // Word is a known proper noun and is allowed to be capitalized + continue + } // First word in error starts with a capital // letter, and the word doesn't contain any other // capitals, making it unlikely to be an diff --git a/stylecheck/st1005/testdata/go1.0/CheckErrorStrings/CheckErrorStrings.go b/stylecheck/st1005/testdata/go1.0/CheckErrorStrings/CheckErrorStrings.go index da8422b11..6a9153f56 100644 --- a/stylecheck/st1005/testdata/go1.0/CheckErrorStrings/CheckErrorStrings.go +++ b/stylecheck/st1005/testdata/go1.0/CheckErrorStrings/CheckErrorStrings.go @@ -15,6 +15,10 @@ func fn() { errors.New("Foo(bar) failed") errors.New("Foo(bar, baz) failed") errors.New("P384 is a nice curve") + errors.New("Docker failed to start") + errors.New("Kubernetes could not schedule the pod") + errors.New("Travis CI blew up, oh noes") + errors.New("Nope is not a proper noun") //@ diag(`error strings should not be capitalized`) } func Write() { diff --git a/website/content/docs/configuration/options.md b/website/content/docs/configuration/options.md index 2cbdd4e84..76f9b88c3 100644 --- a/website/content/docs/configuration/options.md +++ b/website/content/docs/configuration/options.md @@ -26,6 +26,15 @@ set of known initialisms can be configured with this option. Default value: `["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"]` +## proper_nouns {#proper_nouns} + +{{< check "ST1005" >}} flags error strings that start with a capital letter. +Proper nouns are allowed to be capitalized, and this option configures the set +of proper nouns that the check knows about. The match is case-sensitive and only +applies to the first word of the error string. + +Default value: `["Amazon", "Android", "Ansible", "Azure", "Cloudflare", "Consul", "Docker", "Elasticsearch", "Envoy", "Etcd", "Grafana", "Heroku", "Istio", "Jenkins", "Jira", "Kafka", "Kibana", "Kubernetes", "Linux", "Nginx", "Nomad", "Postgres", "Prometheus", "Redis", "Terraform", "Travis", "Vault", "Windows"]` + ## dot_import_whitelist {#dot_import_whitelist} By default, {{< check "ST1001" >}} forbids