99 "go/token"
1010 "go/types"
1111 "go/version"
12+ "iter"
1213 "slices"
1314 "strconv"
1415 "strings"
@@ -320,30 +321,33 @@ func visit(pass *analysis.Pass, opts *Options, node ast.Node, stack []ast.Node)
320321 }
321322
322323 if opts .NoRawKeys {
323- forEachKey (pass .TypesInfo , keys , attrs , func ( key ast. Expr ) {
324+ for key := range AllKeys (pass .TypesInfo , keys , attrs ) {
324325 if sel , ok := key .(* ast.SelectorExpr ); ok {
325326 key = sel .Sel // the key is defined in another package, e.g. pkg.ConstKey.
326327 }
328+
327329 isConst := false
330+
328331 if ident , ok := key .(* ast.Ident ); ok {
329332 if obj := pass .TypesInfo .ObjectOf (ident ); obj != nil {
330333 if _ , ok := obj .(* types.Const ); ok {
331334 isConst = true
332335 }
333336 }
334337 }
338+
335339 if ! isConst {
336340 pass .Reportf (call .Pos (), "raw keys should not be used" )
337341 }
338- })
342+ }
339343 }
340344
341345 checkKeyNamingCase := func (caseFn func (string ) string , caseName string ) {
342- forEachKey (pass .TypesInfo , keys , attrs , func ( key ast. Expr ) {
346+ for key := range AllKeys (pass .TypesInfo , keys , attrs ) {
343347 if name , ok := getKeyName (key ); ok && name != caseFn (name ) {
344348 pass .Reportf (call .Pos (), "keys should be written in %s" , caseName )
345349 }
346- })
350+ }
347351 }
348352
349353 switch opts .KeyNamingCase {
@@ -358,11 +362,11 @@ func visit(pass *analysis.Pass, opts *Options, node ast.Node, stack []ast.Node)
358362 }
359363
360364 if len (opts .ForbiddenKeys ) > 0 {
361- forEachKey (pass .TypesInfo , keys , attrs , func ( key ast. Expr ) {
365+ for key := range AllKeys (pass .TypesInfo , keys , attrs ) {
362366 if name , ok := getKeyName (key ); ok && slices .Contains (opts .ForbiddenKeys , name ) {
363367 pass .Reportf (call .Pos (), "%q key is forbidden and should not be used" , name )
364368 }
365- })
369+ }
366370 }
367371
368372 if opts .ArgsOnSepLines && areArgsOnSameLine (pass .Fset , call , keys , attrs ) {
@@ -444,36 +448,52 @@ func isValidMsgStyle(msg, style string) bool {
444448 }
445449}
446450
447- func forEachKey (info * types.Info , keys , attrs []ast.Expr , fn func (key ast.Expr )) {
448- for _ , key := range keys {
449- fn (key )
450- }
451-
452- for _ , attr := range attrs {
453- switch attr := attr .(type ) {
454- case * ast.CallExpr : // e.g. slog.Int()
455- callee := typeutil .StaticCallee (info , attr )
456- if callee == nil {
457- continue
458- }
459- if _ , ok := attrFuncs [callee .FullName ()]; ! ok {
460- continue
451+ func AllKeys (info * types.Info , keys , attrs []ast.Expr ) iter.Seq [ast.Expr ] {
452+ return func (yield func (key ast.Expr ) bool ) {
453+ for _ , key := range keys {
454+ if ! yield (key ) {
455+ return
461456 }
462- fn (attr .Args [0 ])
457+ }
458+
459+ for _ , attr := range attrs {
460+ switch attr := attr .(type ) {
461+ case * ast.CallExpr : // e.g. slog.Int()
462+ callee := typeutil .StaticCallee (info , attr )
463+ if callee == nil {
464+ continue
465+ }
466+ if _ , ok := attrFuncs [callee .FullName ()]; ! ok {
467+ continue
468+ }
463469
464- case * ast.CompositeLit : // slog.Attr{}
465- switch len (attr .Elts ) {
466- case 1 : // slog.Attr{Key: ...} | slog.Attr{Value: ...}
467- if kv := attr .Elts [0 ].(* ast.KeyValueExpr ); kv .Key .(* ast.Ident ).Name == "Key" {
468- fn (kv .Value )
470+ if ! yield (attr .Args [0 ]) {
471+ return
469472 }
470- case 2 : // slog.Attr{Key: ..., Value: ...} | slog.Attr{Value: ..., Key: ...} | slog.Attr{..., ...}
471- if kv , ok := attr .Elts [0 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
472- fn (kv .Value )
473- } else if kv , ok := attr .Elts [1 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
474- fn (kv .Value )
475- } else {
476- fn (attr .Elts [0 ])
473+
474+ case * ast.CompositeLit : // slog.Attr{}
475+ switch len (attr .Elts ) {
476+ case 1 : // slog.Attr{Key: ...} | slog.Attr{Value: ...}
477+ if kv := attr .Elts [0 ].(* ast.KeyValueExpr ); kv .Key .(* ast.Ident ).Name == "Key" {
478+ if ! yield (kv .Value ) {
479+ return
480+ }
481+ }
482+
483+ case 2 : // slog.Attr{Key: ..., Value: ...} | slog.Attr{Value: ..., Key: ...} | slog.Attr{..., ...}
484+ if kv , ok := attr .Elts [0 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
485+ if ! yield (kv .Value ) {
486+ return
487+ }
488+ } else if kv , ok := attr .Elts [1 ].(* ast.KeyValueExpr ); ok && kv .Key .(* ast.Ident ).Name == "Key" {
489+ if ! yield (kv .Value ) {
490+ return
491+ }
492+ } else {
493+ if ! yield (attr .Elts [0 ]) {
494+ return
495+ }
496+ }
477497 }
478498 }
479499 }
0 commit comments