@@ -22,6 +22,7 @@ type Options struct {
2222 KVOnly bool // Enforce using key-value pairs only (incompatible with AttrOnly).
2323 AttrOnly bool // Enforce using attributes only (incompatible with KVOnly).
2424 ContextOnly bool // Enforce using methods that accept a context.
25+ StaticMsg bool // Enforce using static log messages.
2526 NoRawKeys bool // Enforce using constants instead of raw keys.
2627 KeyNamingCase string // Enforce a single key naming convention ("snake", "kebab", "camel", or "pascal").
2728 ArgsOnSepLines bool // Enforce putting arguments on separate lines.
@@ -71,6 +72,7 @@ func flags(opts *Options) flag.FlagSet {
7172 boolVar (& opts .KVOnly , "kv-only" , "enforce using key-value pairs only (incompatible with -attr-only)" )
7273 boolVar (& opts .AttrOnly , "attr-only" , "enforce using attributes only (incompatible with -kv-only)" )
7374 boolVar (& opts .ContextOnly , "context-only" , "enforce using methods that accept a context" )
75+ boolVar (& opts .StaticMsg , "static-msg" , "enforce using static log messages" )
7476 boolVar (& opts .NoRawKeys , "no-raw-keys" , "enforce using constants instead of raw keys" )
7577 boolVar (& opts .ArgsOnSepLines , "args-on-sep-lines" , "enforce putting arguments on separate lines" )
7678
@@ -146,6 +148,9 @@ func run(pass *analysis.Pass, opts *Options) {
146148 pass .Reportf (call .Pos (), "methods without a context should not be used" )
147149 }
148150 }
151+ if opts .StaticMsg && ! staticMsg (call .Args [argsPos - 1 ]) {
152+ pass .Reportf (call .Pos (), "message should be a string literal or a constant" )
153+ }
149154
150155 // NOTE: we assume that the arguments have already been validated by govet.
151156 args := call .Args [argsPos :]
@@ -199,6 +204,17 @@ func run(pass *analysis.Pass, opts *Options) {
199204 })
200205}
201206
207+ func staticMsg (expr ast.Expr ) bool {
208+ switch msg := expr .(type ) {
209+ case * ast.BasicLit : // e.g. slog.Info("msg")
210+ return msg .Kind == token .STRING
211+ case * ast.Ident : // e.g. const msg = "msg"; slog.Info(msg)
212+ return msg .Obj != nil && msg .Obj .Kind == ast .Con
213+ default :
214+ return false
215+ }
216+ }
217+
202218func rawKeysUsed (info * types.Info , keys , attrs []ast.Expr ) bool {
203219 isConst := func (expr ast.Expr ) bool {
204220 ident , ok := expr .(* ast.Ident )
0 commit comments