Credence.Semantic.PreferExplicitRangeStep (credence v0.8.0)

Copy Markdown

Makes the implicit step of a descending literal range explicit.

Since Elixir 1.19 a fully-literal range whose default step is -1 (first > last, e.g. 1..-2, 10..-5, 5..1) emits a deprecation warning:

1..-2 has a default step of -1, please write 1..-2//-1 instead

Under --warnings-as-errors this blocks compilation. The fix appends //-1, which is a no-op on behaviour: the warning states that -1 is already the current default step, so 1..-2 and 1..-2//-1 are the identical Range value.

Why the fix is AST-based, not text-based

The diagnostic carries no usable positionCode.with_diagnostics reports the range-step deprecation at position 0, with no line or column — and the message normalizes whitespace (a source range 1 .. -2 is reported as 1..-2). A text-replacement fix keyed on the message string would therefore (a) miss spaced ranges entirely and (b) blindly rewrite every occurrence of that text — including the same digits sitting inside a string literal, atom, or comment — silently changing a value. That is a behaviour change, not a no-op.

Instead the fix parses the source and rewrites only genuine range operator nodes ({:.., _, [lo, hi]}) whose two endpoints are integer literals (or the unary minus of one) with lo > hi — exactly the inputs the compiler warns on, and the only inputs for which the default step is -1. Strings, charlists, atoms and comments carry no .. operator node, so they are never touched. A range with a non-literal endpoint (a..-1) produces no diagnostic and matches no node, so it is left alone.