Skip to content

linter: L006 and text-based L009 results depend on map iteration order #618

Closed

Description

@ajitpratap0

Summary

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:

SELECT users.id, orders.total
FROM users u
JOIN orders ON users.id = orders.uid
WHERE (

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.

Found during review of #588, #585.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglinter

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions