55 "fmt"
66 "go/ast"
77 "go/types"
8- "maps"
9- "reflect"
108 "runtime"
119 "slices"
1210 "strings"
@@ -19,7 +17,6 @@ import (
1917
2018 "github.com/golangci/golangci-lint/v2/pkg/config"
2119 "github.com/golangci/golangci-lint/v2/pkg/goanalysis"
22- "github.com/golangci/golangci-lint/v2/pkg/golinters/internal"
2320 "github.com/golangci/golangci-lint/v2/pkg/lint/linter"
2421 "github.com/golangci/golangci-lint/v2/pkg/logutils"
2522)
3128 isDebug = logutils .HaveDebugTag (logutils .DebugKeyGoCritic )
3229)
3330
34- func New (settings * config.GoCriticSettings ) * goanalysis.Linter {
31+ func New (settings * config.GoCriticSettings , replacer * strings. Replacer ) * goanalysis.Linter {
3532 wrapper := & goCriticWrapper {
3633 sizes : types .SizesFor ("gc" , runtime .GOARCH ),
3734 }
@@ -58,23 +55,18 @@ Dynamic rules are written declaratively with AST patterns, filters, report messa
5855 nil ,
5956 ).
6057 WithContextSetter (func (context * linter.Context ) {
61- wrapper .replacer = strings .NewReplacer (
62- internal .PlaceholderBasePath , context .Cfg .GetBasePath (),
63- )
64-
65- wrapper .init (context .Log , settings )
58+ wrapper .init (context .Log , settings , replacer )
6659 }).
6760 WithLoadMode (goanalysis .LoadModeTypesInfo )
6861}
6962
7063type goCriticWrapper struct {
7164 settingsWrapper * settingsWrapper
72- replacer * strings.Replacer
7365 sizes types.Sizes
7466 once sync.Once
7567}
7668
77- func (w * goCriticWrapper ) init (logger logutils.Log , settings * config.GoCriticSettings ) {
69+ func (w * goCriticWrapper ) init (logger logutils.Log , settings * config.GoCriticSettings , replacer * strings. Replacer ) {
7870 if settings == nil {
7971 return
8072 }
@@ -86,12 +78,9 @@ func (w *goCriticWrapper) init(logger logutils.Log, settings *config.GoCriticSet
8678 }
8779 })
8880
89- settingsWrapper := newSettingsWrapper (settings , logger )
90- settingsWrapper .InferEnabledChecks ()
81+ settingsWrapper := newSettingsWrapper (logger , settings , replacer )
9182
92- // Validate must be after InferEnabledChecks, not before.
93- // Because it uses gathered information about tags set and finally enabled checks.
94- if err := settingsWrapper .Validate (); err != nil {
83+ if err := settingsWrapper .Load (); err != nil {
9584 logger .Fatalf ("%s: invalid settings: %s" , linterName , err )
9685 }
9786
@@ -140,7 +129,8 @@ func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context
140129 continue
141130 }
142131
143- if err := w .configureCheckerInfo (info , allLowerCasedParams ); err != nil {
132+ err := w .settingsWrapper .setCheckerParams (info , allLowerCasedParams )
133+ if err != nil {
144134 return nil , err
145135 }
146136
@@ -155,59 +145,6 @@ func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context
155145 return enabledCheckers , nil
156146}
157147
158- func (w * goCriticWrapper ) configureCheckerInfo (
159- info * gocriticlinter.CheckerInfo ,
160- allLowerCasedParams map [string ]config.GoCriticCheckSettings ,
161- ) error {
162- params := allLowerCasedParams [strings .ToLower (info .Name )]
163- if params == nil { // no config for this checker
164- return nil
165- }
166-
167- // To lowercase info param keys here because golangci-lint's config parser lowercases all strings.
168- infoParams := normalizeMap (info .Params )
169- for k , p := range params {
170- v , ok := infoParams [k ]
171- if ok {
172- v .Value = w .normalizeCheckerParamsValue (p )
173- continue
174- }
175-
176- // param `k` isn't supported
177- if len (info .Params ) == 0 {
178- return fmt .Errorf ("checker %s config param %s doesn't exist: checker doesn't have params" ,
179- info .Name , k )
180- }
181-
182- supportedKeys := slices .Sorted (maps .Keys (info .Params ))
183-
184- return fmt .Errorf ("checker %s config param %s doesn't exist, all existing: %s" ,
185- info .Name , k , supportedKeys )
186- }
187-
188- return nil
189- }
190-
191- // normalizeCheckerParamsValue normalizes value types.
192- // go-critic asserts that CheckerParam.Value has some specific types,
193- // but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type.
194- // then we have to convert value types into the expected value types.
195- // Maybe in the future, this kind of conversion will be done in go-critic itself.
196- func (w * goCriticWrapper ) normalizeCheckerParamsValue (p any ) any {
197- rv := reflect .ValueOf (p )
198- switch rv .Type ().Kind () {
199- case reflect .Int64 , reflect .Int32 , reflect .Int16 , reflect .Int8 , reflect .Int :
200- return int (rv .Int ())
201- case reflect .Bool :
202- return rv .Bool ()
203- case reflect .String :
204- // Perform variable substitution.
205- return w .replacer .Replace (rv .String ())
206- default :
207- return p
208- }
209- }
210-
211148func runOnFile (pass * analysis.Pass , f * ast.File , checks []* gocriticlinter.Checker ) {
212149 for _ , c := range checks {
213150 // All checkers are expected to use *lint.Context
@@ -233,19 +170,3 @@ func runOnFile(pass *analysis.Pass, f *ast.File, checks []*gocriticlinter.Checke
233170 }
234171 }
235172}
236-
237- func normalizeMap [ValueT any ](in map [string ]ValueT ) map [string ]ValueT {
238- ret := make (map [string ]ValueT , len (in ))
239- for k , v := range in {
240- ret [strings .ToLower (k )] = v
241- }
242- return ret
243- }
244-
245- func isEnabledByDefaultGoCriticChecker (info * gocriticlinter.CheckerInfo ) bool {
246- // https://github.com/go-critic/go-critic/blob/5b67cfd487ae9fe058b4b19321901b3131810f65/cmd/gocritic/check.go#L342-L345
247- return ! info .HasTag (gocriticlinter .ExperimentalTag ) &&
248- ! info .HasTag (gocriticlinter .OpinionatedTag ) &&
249- ! info .HasTag (gocriticlinter .PerformanceTag ) &&
250- ! info .HasTag (gocriticlinter .SecurityTag )
251- }
0 commit comments