From 0ba1388a4194525dfea1e8b91211c49de9d260f2 Mon Sep 17 00:00:00 2001
From: Sasha Melentyev <sasha@melentyev.io>
Date: Wed, 3 Aug 2022 12:13:50 +0300
Subject: [PATCH] feat: add usestdlibvars (#3016)

---
 .golangci.reference.yml        | 25 +++++++++++++++++++++++++
 go.mod                         |  1 +
 go.sum                         |  2 ++
 pkg/config/linters_settings.go | 11 +++++++++++
 pkg/golinters/usestdlibvars.go | 33 +++++++++++++++++++++++++++++++++
 pkg/lint/lintersdb/manager.go  |  6 ++++++
 test/testdata/usestdlibvars.go | 13 +++++++++++++
 7 files changed, 91 insertions(+)
 create mode 100644 pkg/golinters/usestdlibvars.go
 create mode 100644 test/testdata/usestdlibvars.go

diff --git a/.golangci.reference.yml b/.golangci.reference.yml
index 29651c09..27123e64 100644
--- a/.golangci.reference.yml
+++ b/.golangci.reference.yml
@@ -1669,6 +1669,29 @@ linters-settings:
       # Default: true
       begin: false
 
+  usestdlibvars:
+    # Suggest the use of http.MethodXX
+    # Default: true
+    http-method: false
+    # Suggest the use of http.StatusXX
+    # Default: true
+    http-status-code: false
+    # Suggest the use of time.Weekday
+    # Default: true
+    time-weekday: true
+    # Suggest the use of time.Month
+    # Default: false
+    time-month: true
+    # Suggest the use of time.Layout
+    # Default: false
+    time-layout: true
+    # Suggest the use of crypto.Hash
+    # Default: false
+    crypto-hash: true
+    # Suggest the use of pc.DefaultXXPath
+    # Default: false
+    default-rpc-path: true
+
   unparam:
     # Inspect exported functions.
     #
@@ -1934,6 +1957,7 @@ linters:
     - unconvert
     - unparam
     - unused
+    - usestdlibvars
     - varcheck
     - varnamelen
     - wastedassign
@@ -2035,6 +2059,7 @@ linters:
     - unconvert
     - unparam
     - unused
+    - usestdlibvars
     - varcheck
     - varnamelen
     - wastedassign
diff --git a/go.mod b/go.mod
index d5828610..259f16a4 100644
--- a/go.mod
+++ b/go.mod
@@ -74,6 +74,7 @@ require (
 	github.com/ryancurrah/gomodguard v1.2.4
 	github.com/ryanrolds/sqlclosecheck v0.3.0
 	github.com/sanposhiho/wastedassign/v2 v2.0.6
+	github.com/sashamelentyev/usestdlibvars v1.8.0
 	github.com/securego/gosec/v2 v2.12.0
 	github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c
 	github.com/shirou/gopsutil/v3 v3.22.6
diff --git a/go.sum b/go.sum
index f7a2f59b..aefdfdb5 100644
--- a/go.sum
+++ b/go.sum
@@ -600,6 +600,8 @@ github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8
 github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
 github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA=
 github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
+github.com/sashamelentyev/usestdlibvars v1.8.0 h1:QnWP9IOEuRyYKH+IG0LlQIjuJlc0rfdo4K3/Zh3WRMw=
+github.com/sashamelentyev/usestdlibvars v1.8.0/go.mod h1:BFt7b5mSVHaaa26ZupiNRV2ODViQBxZZVhtAxAJRrjs=
 github.com/securego/gosec/v2 v2.12.0 h1:CQWdW7ATFpvLSohMVsajscfyHJ5rsGmEXmsNcsDNmAg=
 github.com/securego/gosec/v2 v2.12.0/go.mod h1:iTpT+eKTw59bSgklBHlSnH5O2tNygHMDxfvMubA4i7I=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go
index d4dfcfea..3c356b40 100644
--- a/pkg/config/linters_settings.go
+++ b/pkg/config/linters_settings.go
@@ -178,6 +178,7 @@ type LintersSettings struct {
 	Thelper          ThelperSettings
 	Unparam          UnparamSettings
 	Unused           StaticCheckSettings
+	UseStdlibVars    UseStdlibVarsSettings
 	Varcheck         VarCheckSettings
 	Varnamelen       VarnamelenSettings
 	Whitespace       WhitespaceSettings
@@ -587,6 +588,16 @@ type TenvSettings struct {
 	All bool `mapstructure:"all"`
 }
 
+type UseStdlibVarsSettings struct {
+	HTTPMethod         bool `mapstructure:"http-method"`
+	HTTPStatusCode     bool `mapstructure:"http-status-code"`
+	TimeWeekday        bool `mapstructure:"time-weekday"`
+	TimeMonth          bool `mapstructure:"time-month"`
+	TimeLayout         bool `mapstructure:"time-layout"`
+	CryptoHash         bool `mapstructure:"crypto-hash"`
+	DefaultRPCPathFlag bool `mapstructure:"default-rpc-path"`
+}
+
 type UnparamSettings struct {
 	CheckExported bool `mapstructure:"check-exported"`
 	Algo          string
diff --git a/pkg/golinters/usestdlibvars.go b/pkg/golinters/usestdlibvars.go
new file mode 100644
index 00000000..dbb6d953
--- /dev/null
+++ b/pkg/golinters/usestdlibvars.go
@@ -0,0 +1,33 @@
+package golinters
+
+import (
+	"github.com/sashamelentyev/usestdlibvars/pkg/analyzer"
+	"golang.org/x/tools/go/analysis"
+
+	"github.com/golangci/golangci-lint/pkg/config"
+	"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
+)
+
+func NewUseStdlibVars(cfg *config.UseStdlibVarsSettings) *goanalysis.Linter {
+	a := analyzer.New()
+
+	cfgMap := make(map[string]map[string]interface{})
+	if cfg != nil {
+		cfgMap[a.Name] = map[string]interface{}{
+			analyzer.HTTPMethodFlag:     cfg.HTTPMethod,
+			analyzer.HTTPStatusCodeFlag: cfg.HTTPStatusCode,
+			analyzer.TimeWeekdayFlag:    cfg.TimeWeekday,
+			analyzer.TimeMonthFlag:      cfg.TimeMonth,
+			analyzer.TimeLayoutFlag:     cfg.TimeLayout,
+			analyzer.CryptoHashFlag:     cfg.CryptoHash,
+			analyzer.DefaultRPCPathFlag: cfg.DefaultRPCPathFlag,
+		}
+	}
+
+	return goanalysis.NewLinter(
+		a.Name,
+		a.Doc,
+		[]*analysis.Analyzer{a},
+		cfgMap,
+	).WithLoadMode(goanalysis.LoadModeSyntax)
+}
diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go
index 2d5174e5..3182e31f 100644
--- a/pkg/lint/lintersdb/manager.go
+++ b/pkg/lint/lintersdb/manager.go
@@ -164,6 +164,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
 		thelperCfg          *config.ThelperSettings
 		unparamCfg          *config.UnparamSettings
 		unusedCfg           *config.StaticCheckSettings
+		usestdlibvars       *config.UseStdlibVarsSettings
 		varcheckCfg         *config.VarCheckSettings
 		varnamelenCfg       *config.VarnamelenSettings
 		whitespaceCfg       *config.WhitespaceSettings
@@ -767,6 +768,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
 			WithChangeTypes().
 			WithURL("https://github.com/dominikh/go-tools/tree/master/unused"),
 
+		linter.NewConfig(golinters.NewUseStdlibVars(usestdlibvars)).
+			WithSince("v1.48.0").
+			WithPresets(linter.PresetStyle).
+			WithURL("https://github.com/sashamelentyev/usestdlibvars"),
+
 		linter.NewConfig(golinters.NewVarcheck(varcheckCfg)).
 			WithSince("v1.0.0").
 			WithLoadForGoAnalysis().
diff --git a/test/testdata/usestdlibvars.go b/test/testdata/usestdlibvars.go
new file mode 100644
index 00000000..c3c4e463
--- /dev/null
+++ b/test/testdata/usestdlibvars.go
@@ -0,0 +1,13 @@
+//golangcitest:args -Eusestdlibvars
+package testdata
+
+import "net/http"
+
+func _200() {
+	_ = 200
+}
+
+func _200_1() {
+	var w http.ResponseWriter
+	w.WriteHeader(200) // ERROR `"200" can be replaced by http.StatusOK`
+}