Credence.Pattern.InconsistentParamNames (credence v0.7.0)

Copy Markdown

Detects functions where the same positional parameter uses different variable names across clauses.

Why this matters

LLMs generate function clauses semi-independently, often drifting parameter names between clauses of the same function:

# Flagged — first arg is "current" in one clause, "prev" in another
defp do_fibonacci(current, _next, 0), do: current
defp do_fibonacci(prev, current, steps), do: do_fibonacci(current, prev + current, steps - 1)

# Consistent — same name at each position across all clauses
defp do_fibonacci(prev, _current, 0), do: prev
defp do_fibonacci(prev, current, steps), do: do_fibonacci(current, prev + current, steps - 1)

Inconsistent names make the reader question whether the function is correct — if the first argument is called current in one clause and prev in another, which is it?

Auto-fix strategy

The first clause establishes canonical base names. Subsequent clauses are renamed to match. Underscore prefixes are preserved: if a clause uses _banana and the canonical base is number, it becomes _number.

Bare _ and non-variable patterns (literals, destructuring) at a given position cause that position to be skipped entirely.

Pattern-match equality between arguments

When the same variable name appears at multiple argument positions within one clause — top-level or nested inside a tuple, list, map, struct, or binary — Elixir enforces equality between those positions:

def validate(errors, q, ans, ans), do: errors  # 3rd arg must equal 4th
def lookup(id, %User{id: id}), do: id          # top-level arg must equal nested field

Such names are load-bearing. Renaming one occurrence breaks the equality; renaming a free name in another clause to the same target invents an equality that wasn't there. Whenever any clause in a group has such an intra-clause name sharing, every position that participates is skipped — for both detection and renaming — so the rule never produces an unsafe fix.