You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
linter: L006 and text-based L009 results depend on map iteration order #618
Two linter rules build their output by iterating Go maps, so the same input gives different results from run to run. L006 (Column Alignment) breaks ties between indent widths in map order, so the line it flags changes between runs. The text-based fallback of L009 (Aliasing Consistency) emits its violations in map order, so the order of violations from Lint changes between runs.
Reproduction
L006, where two continuation lines have different indents (2 and 4) and each indent appears once:
SELECT a,
b,
c
FROM t
go build -o gosqlx ./cmd/gosqlx
for i in $(seq 10); do ./gosqlx lint l006.sql | grep L006; done | sort | uniq -c
1 [L006] Column Alignment at line 2, column 3
9 [L006] Column Alignment at line 3, column 5
I also called gosqlx.Lint 20 times in a process and repeated that in 20 separate processes. The split between 2:3 and 3:5 changed in every process, from {2:3:1, 3:5:19} to {3:5:20}.
L009 text-based fallback, which runs when the SQL does not parse:
SELECTusers.id, orders.totalFROM users u
JOIN orders ONusers.id=orders.uidWHERE (
Over 20 gosqlx.Lint calls in one process I got L009@2:1 L009@3:1 16 times and L009@3:1 L009@2:1 4 times.
Expected: the same violations, at the same positions and in the same order, on every run.
Notes
pkg/linter/rules/style/column_alignment.go:167-179: expectedIndent is chosen with for indent, count := range indentCounts, and a tie goes to whichever key the map yields first. Break ties deterministically, for example by the smallest indent or the indent of the first continuation line.
pkg/linter/rules/style/aliasing_consistency.go:180: for tableName, definedLine := range fullTableNames appends violations in map order. The inner loop range definedAliases only produces a bool, so its order does not matter. Iterate in source order, for example by keeping a slice of table names in the order they were seen, or sort the violations by line.
The rules themselves run in a fixed order (pkg/linter/linter.go:250). Optionally, LintString could sort violations by (line, column, rule) so every rule's output is stable.
Activity
fix(linter): make L006 tie-break and text-based L009 order determinis…
fix(linter,gosqlx): deterministic L006/L009 and Extract* result order (…