99 "go/token"
1010 "go/types"
1111 "go/version"
12+ "iter"
1213 "slices"
1314 "strconv"
1415 "strings"
@@ -302,32 +303,35 @@ func visit(pass *analysis.Pass, opts *Options, node ast.Node, stack []ast.Node)
302303 }
303304
304305 if opts .NoRawKeys {
305- forEachKey (pass .TypesInfo , keys , attrs , func ( key ast. Expr ) {
306+ for key := range AllKeys (pass .TypesInfo , keys , attrs ) {
306307 if sel , ok := key .(* ast.SelectorExpr ); ok {
307308 key = sel .Sel // the key is defined in another package, e.g. pkg.ConstKey.
308309 }
310+
309311 isConst := false
312+
310313 if ident , ok := key .(* ast.Ident ); ok {
311314 if obj := pass .TypesInfo .ObjectOf (ident ); obj != nil {
312315 if _ , ok := obj .(* types.Const ); ok {
313316 isConst = true
314317 }
315318 }
316319 }
320+
317321 if ! isConst {
318322 pass .Reportf (key .Pos (), "raw keys should not be used" )
319323 }
320- })
324+ }
321325 }
322326
323327 checkKeysNaming (opts , pass , keys , attrs )
324328
325329 if len (opts .ForbiddenKeys ) > 0 {
326- forEachKey (pass .TypesInfo , keys , attrs , func ( key ast. Expr ) {
330+ for key := range AllKeys (pass .TypesInfo , keys , attrs ) {
327331 if name , ok := getKeyName (key ); ok && slices .Contains (opts .ForbiddenKeys , name ) {
328332 pass .Reportf (key .Pos (), "%q key is forbidden and should not be used" , name )
329333 }
330- })
334+ }
331335 }
332336
333337 if opts .ArgsOnSepLines && areArgsOnSameLine (pass .Fset , call , keys , attrs ) {
@@ -337,7 +341,7 @@ func visit(pass *analysis.Pass, opts *Options, node ast.Node, stack []ast.Node)
337341
338342func checkKeysNaming (opts * Options , pass * analysis.Pass , keys , attrs []ast.Expr ) {
339343 checkKeyNamingCase := func (caseFn func (string ) string , caseName string ) {
340- forEachKey (pass .TypesInfo , keys , attrs , func ( key ast. Expr ) {
344+ for key := range AllKeys (pass .TypesInfo , keys , attrs ) {
341345 name , ok := getKeyName (key )
342346 if ! ok || name == caseFn (name ) {
343347 return
@@ -354,7 +358,7 @@ func checkKeysNaming(opts *Options, pass *analysis.Pass, keys, attrs []ast.Expr)
354358 }},
355359 }},
356360 })
357- })
361+ }
358362 }
359363
360364 switch opts .KeyNamingCase {
@@ -479,36 +483,52 @@ func isValidMsgStyle(msg, style string) bool {
479483 }
480484}
481485
482- func forEachKey (info * types.Info , keys , attrs []ast.Expr , fn func (key ast.Expr )) {
483- for _ , key := range keys {
484- fn (key )
485- }
486-
487- for _ , attr := range attrs {
488- switch attr := attr .(type ) {
489- case * ast.CallExpr : // e.g. slog.Int()
490- callee := typeutil .StaticCallee (info , attr )
491- if callee == nil {
492- continue
493- }
494- if _ , ok := attrFuncs [callee .FullName ()]; ! ok {
495- continue
486+ func AllKeys (info * types.Info , keys , attrs []ast.Expr ) iter.Seq [ast.Expr ] {
487+ return func (yield func (key ast.Expr ) bool ) {
488+ for _ , key := range keys {
489+ if ! yield (key ) {
490+ return
496491 }
497- fn (attr .Args [0 ])
492+ }
493+
494+ for _ , attr := range attrs {
495+ switch attr := attr .(type ) {
496+ case * ast.CallExpr : // e.g. slog.Int()
497+ callee := typeutil .StaticCallee (info , attr )
498+ if callee == nil {
499+ continue
500+ }
501+ if _ , ok := attrFuncs [callee .FullName ()]; ! ok {
502+ continue
503+ }
498504
499- case * ast.CompositeLit : // slog.Attr{}
500- switch len (attr .Elts ) {
501- case 1 : // slog.Attr{Key: ...} | slog.Attr{Value: ...}
502- if kv := attr .Elts [0 ].(* ast.KeyValueExpr ); kv .Key .(* ast.Ident ).Name == "Key" {
503- fn (kv .Value )
505+ if ! yield (attr .Args [0 ]) {
506+ return
504507 }
505- case 2 : // slog.Attr{Key: ..., Value: ...} | slog.Attr{Value: ..., Key: ...} | slog.Attr{..., ...}
506- if kv , ok := attr .Elts [0 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
507- fn (kv .Value )
508- } else if kv , ok := attr .Elts [1 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
509- fn (kv .Value )
510- } else {
511- fn (attr .Elts [0 ])
508+
509+ case * ast.CompositeLit : // slog.Attr{}
510+ switch len (attr .Elts ) {
511+ case 1 : // slog.Attr{Key: ...} | slog.Attr{Value: ...}
512+ if kv := attr .Elts [0 ].(* ast.KeyValueExpr ); kv .Key .(* ast.Ident ).Name == "Key" {
513+ if ! yield (kv .Value ) {
514+ return
515+ }
516+ }
517+
518+ case 2 : // slog.Attr{Key: ..., Value: ...} | slog.Attr{Value: ..., Key: ...} | slog.Attr{..., ...}
519+ if kv , ok := attr .Elts [0 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
520+ if ! yield (kv .Value ) {
521+ return
522+ }
523+ } else if kv , ok := attr .Elts [1 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
524+ if ! yield (kv .Value ) {
525+ return
526+ }
527+ } else {
528+ if ! yield (attr .Elts [0 ]) {
529+ return
530+ }
531+ }
512532 }
513533 }
514534 }
0 commit comments