Credence.Pattern.NoMapKeysEnumLookup
(credence v0.8.0)
Copy Markdown
Detects Map.keys(var) piped into an Enum function whose callback
also looks up values from the same map variable.
Why this matters
LLMs frequently port the Python idiom for key in dict: ... dict[key]
into Elixir as Map.keys(map) |> Enum.xxx(fn k -> ... map[k] ... end).
This creates an unnecessary intermediate list and performs redundant
lookups. In Elixir, maps are directly enumerable as {key, value}
pairs:
# Flagged — extra allocation + redundant lookups
Map.keys(freqs)
|> Enum.all?(fn char -> Map.get(other, char, 0) >= freqs[char] end)
# Idiomatic — single traversal, values already in hand
Enum.all?(freqs, fn {char, count} ->
Map.get(other, char, 0) >= count
end)Detection scope (strict)
Only flagged when all three conditions hold:
Map.keys(var)is called on a simple variable,- The result is passed to
Enum.all?orEnum.any?, and - The callback body references
varviavar[key],Map.get(var, ...),Map.fetch(var, ...), orMap.fetch!(var, ...).
Patterns where only keys are needed (no value lookup in the callback) are not flagged.
Only all?/any? are flagged because their result is a boolean — a
commutative AND/OR over the elements — so iterating the map directly (a
different order than Map.keys/1 once a map exceeds 32 entries) gives the
same answer. map/filter/reject/flat_map return order-observable lists
and each's side effects are order-sensitive, so rewriting them would not be
behaviour-preserving and they are left alone.