fix(rules): make magic-number detection far less noisy

Real-world test on a 321-file TS/Svelte monorepo flagged 454 magic-number
findings, ~82% of them noise: literals already assigned to a named const/field
and numbers merely buried under a binary expression (e.g. a call arg inside a
string concat). Tighten all 5 languages to: (1) require the literal be a DIRECT
operand of a binary/comparison expression, and (2) exclude initializers of a
named binding (const/var/let/field). Cuts magic-number ~67% with no loss on
fixtures (each language still detects its genuine `x > 5000` case).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Giancarmine Salucci
2026-06-23 01:32:33 +02:00
co-authored by Claude Opus 4.8
parent 6fb2210bbe
commit 8324dde1a2
6 changed files with 41 additions and 38 deletions
+7 -6
View File
@@ -30,9 +30,10 @@ language: Go
severity: info severity: info
message: "Magic number in an expression — consider a named constant." message: "Magic number in an expression — consider a named constant."
rule: rule:
kind: int_literal all:
not: - kind: int_literal
regex: "^(0|1|2|10|100|1000)$" - not: { regex: "^(0|1|2|10|100|1000)$" }
inside: - inside: { kind: binary_expression }
kind: binary_expression # Skip literals already named via const/var declaration.
stopBy: end - not: { inside: { kind: const_spec, stopBy: end } }
- not: { inside: { kind: var_spec, stopBy: end } }
+6 -6
View File
@@ -30,9 +30,9 @@ language: Java
severity: info severity: info
message: "Magic number in an expression — consider a named constant." message: "Magic number in an expression — consider a named constant."
rule: rule:
kind: decimal_integer_literal all:
not: - kind: decimal_integer_literal
regex: "^(0|1|2|10|100|1000)$" - not: { regex: "^(0|1|2|10|100|1000)$" }
inside: - inside: { kind: binary_expression }
kind: binary_expression # Skip literals already named via field/variable declaration.
stopBy: end - not: { inside: { kind: variable_declarator, stopBy: end } }
+6 -6
View File
@@ -30,9 +30,9 @@ language: JavaScript
severity: info severity: info
message: "Magic number in an expression — consider a named constant." message: "Magic number in an expression — consider a named constant."
rule: rule:
kind: number all:
not: - kind: number
regex: "^(0|1|2|-1|10|100|1000)$" - not: { regex: "^(0|1|2|-1|10|100|1000)$" }
inside: - inside: { kind: binary_expression }
kind: binary_expression - not: { inside: { kind: variable_declarator, stopBy: end } }
stopBy: end - not: { inside: { kind: field_definition, stopBy: end } }
+6 -8
View File
@@ -33,11 +33,9 @@ language: Python
severity: info severity: info
message: "Magic number in an expression — consider a named constant." message: "Magic number in an expression — consider a named constant."
rule: rule:
kind: integer all:
not: - kind: integer
regex: "^(0|1|2|10|100|1000)$" - not: { regex: "^(0|1|2|10|100|1000)$" }
inside: - inside: { any: [{ kind: binary_operator }, { kind: comparison_operator }] }
any: # Skip literals already named via assignment (e.g. `RETRIES = 5`).
- kind: binary_operator - not: { inside: { kind: assignment, stopBy: end } }
- kind: comparison_operator
stopBy: end
+7 -6
View File
@@ -31,9 +31,10 @@ language: Rust
severity: info severity: info
message: "Magic number in an expression — consider a named constant." message: "Magic number in an expression — consider a named constant."
rule: rule:
kind: integer_literal all:
not: - kind: integer_literal
regex: "^(0|1|2|10|100|1000)$" - not: { regex: "^(0|1|2|10|100|1000)$" }
inside: - inside: { kind: binary_expression }
kind: binary_expression # Skip literals already named via `let`/`const`/`static` declaration.
stopBy: end - not: { inside: { kind: let_declaration, stopBy: end } }
- not: { inside: { kind: const_item, stopBy: end } }
+9 -6
View File
@@ -38,9 +38,12 @@ severity: info
message: "Magic number in an expression — consider a named constant." message: "Magic number in an expression — consider a named constant."
metadata: { pattern: magic-number, apply_track: llm, difficulty: semantic } metadata: { pattern: magic-number, apply_track: llm, difficulty: semantic }
rule: rule:
kind: number all:
not: - kind: number
regex: "^(0|1|2|-1|10|100|1000)$" - not: { regex: "^(0|1|2|-1|10|100|1000)$" }
inside: # Must be a DIRECT operand of a comparison/arithmetic expression (e.g. `x > 5000`),
kind: binary_expression # not just buried under one (avoids flagging call args inside a concat, etc.).
stopBy: end - inside: { kind: binary_expression }
# Skip literals that already have a name: the value of `const X = ...` or a class field.
- not: { inside: { kind: variable_declarator, stopBy: end } }
- not: { inside: { kind: public_field_definition, stopBy: end } }