API Reference credence v#0.6.0
Copy MarkdownModules
Credence — Semantic Linter for Elixir.
Finds the closest matching defined function for an undefined function call.
Defines the structured issue format for any rule violations.
Pattern phase — detects and fixes anti-patterns in Elixir code.
Performance rule: Detects Enum.count/1 on the result of
String.graphemes/1 (without a predicate).
Performance rule: Detects the use of length/1 on the result of
String.graphemes/1.
Fixes calls to guard functions that don't exist in Elixir.
Detects functions where the same positional parameter uses different variable names across clauses.
Readability rule: Detects anonymous functions applied with .() inside
a pipeline.
Detects case expr do true -> …; false -> … end that should be if/else.
Detects cond with exactly two clauses where the second guard is
true — a pattern that is just an if/else in disguise.
Detects patterns where a list is destructured into individual variables and then immediately reassembled into the same list.
Style rule: Detects @doc false placed before private functions (defp).
Performance rule: Detects sorting the same list twice — once ascending and
once descending — when a single sort plus Enum.reverse/1 would suffice.
Performance rule: Detects Enum.with_index/1 passed directly as the
enumerable argument to Enum.reduce/3 (or piped into it).
Performance rule: Flags Enum.at/2 with a midpoint index inside
non-recursive functions.
Detects Enum.at/2 called with a negative integer literal index.
Detects Enum.count/1 (without a predicate) and suggests length/1
or a more specific size function.
Performance rule: Detects Enum.drop(list, -n) where n is a positive
integer literal.
Performance rule: Detects Enum.take(list, -n) where n is a positive
integer literal.
Strict semantic rule: Flags ONLY explicit max-reduction patterns inside Enum.reduce/3.
Flags explicit min-reduction patterns inside Enum.reduce/3.
Flags explicit sum-reduction patterns inside Enum.reduce/3.
Readability & performance rule: Detects the pattern of decomposing a string
into graphemes or a charlist, only to compare it with its own Enum.reverse.
Readability rule: Detects guard clauses that compare a parameter to a
literal value with == when pattern matching in the function head would
be clearer and more idiomatic.
Detects identity arithmetic used to coerce an integer to a float.
Detects Enum._by functions called with an identity function callback,
which can be simplified to the non-_by variant.
Performance rule: Detects converting an integer to a string representation
in a given base and then to a charlist, when Integer.digits/2 can extract
the digits directly as a list of integers.
Detects is_nil(param) in function guards that can be replaced with
pattern matching nil directly in the function head.
Detects def/defp functions with an is_ prefix, which in Elixir
is reserved for guard-safe functions defined with defguard or Erlang BIFs.
Detects qualified Kernel.op/2 calls used as steps in a pipeline.
Idiomatic rule: fixes variables that shadow Kernel functions.
Detects Keyword.get(list, integer) where the key is an integer literal.
Detects n = length(list) followed by Enum.at(list, n - K) — a Python
list[len(list) - 1] idiom. Elixir's Enum.at/2 natively supports
negative indices, so Enum.at(list, -1) is the idiomatic equivalent.
Detects length(list) comparisons with small integers (0–5) that can be
replaced with O(1) pattern matching.
Refactoring rule: Detects guards that check list length with a literal comparison that can be replaced by a pattern match in the function head.
Performance rule: Detects acc ++ [expr] passed directly in a recursive
tail call, where a matching base case returns the accumulator.
Performance rule: Detects acc ++ [expr] as the return value inside
Enum.reduce/3 when the initial accumulator is [].
Detects usage of List.foldl/3 and List.foldr/3 and suggests
Enum.reduce/3 instead.
Performance & style rule: Detects converting a list to a tuple via
List.to_tuple/1 and then accessing elements with elem/2.
Tuples are meant for small, fixed-size collections. Copying a
dynamically-sized list into a tuple just for one-shot indexed access
defeats the purpose and allocates a full copy of the data. Use pattern
matching ([a, b | _] = list) or Enum.at/2 on the list directly instead.
For string processing, use binary_part/3 or binary pattern matching.
Performance and idiomatic code rule: warns when Enum.uniq/1 is manually
reimplemented using Enum.reduce/3 and MapSet.
Readability rule: Detects manual frequency counting with
Enum.reduce(list, %{}, fn x, acc -> Map.update(acc, x, 1, ...) end).
Detects hand-rolled reimplementations of List.last/1.
Detects if expressions that manually reimplement Kernel.max/2.
Detects if expressions that manually reimplement Kernel.min/2.
Readability & performance rule: Detects the pattern
String.graphemes(s) |> Enum.reverse() |> Enum.join() (and the nested
equivalent Enum.join(Enum.reverse(String.graphemes(s)))) which is a manual
reimplementation of String.reverse/1.
Detects Map.get(map, key, -1) followed by a comparison against
the sentinel — a Python dict.get(key, -1) idiom that leaks into
LLM-generated Elixir.
Detects Map.keys(var) piped into an Enum function whose callback
also looks up values from the same map variable.
Performance rule: Detects Map.values(map) or Map.keys(map) passed
directly into an Enum function, which creates an unnecessary intermediate
list.
Detects Enum.map/2 immediately followed by a terminal aggregation
like Enum.max/1, Enum.min/1, or Enum.sum/1, which creates an
unnecessary intermediate list.
Performance rule: Detects calling Map.update/4 (or Map.update!/3) on a
map variable and then immediately reading the same key back with
Map.fetch!/2 or Map.get/2.
Detects Logger macro calls without a require Logger in the enclosing module.
Detects Enum.member?/2 calls nested inside another Enum.* traversal
of the same enumerable and rewrites them to use MapSet.member?/2.
Style & correctness rule: Detects rebinding of parameter names inside
anonymous function (fn) bodies.
When a variable from the parameter destructure is rebound inside the body,
readers lose track of which binding is "live" at each point. This is a
common source of subtle bugs, especially in Enum.reduce callbacks where
the accumulator is destructured.
Detects Regex.replace used as a pipe target and replaces it with
String.replace, which accepts the string as its first argument.
Detects a variable (or tuple/list of plain variables) being assigned and immediately returned as the last two statements of a block.
Detects string literals needlessly wrapped in <<>> binary syntax.
Readability rule: Detects Enum.join("") and Enum.map_join("", mapper)
where the empty-string separator is passed explicitly.
Detects multiple traversals of the same list that could be merged into a single pass.
Detects guard clauses that are logically redundant because a preceding clause of the same function already handles the complementary case.
Detects inefficient patterns where a full sort is performed only to retrieve a single element (the minimum or maximum).
Performance rule (fixable): Detects Enum.sort |> Enum.at(index) where the
index is a literal 0 or -1 and the sort direction can be statically
determined. These can be safely replaced with Enum.min/1 or Enum.max/1,
avoiding the O(n log n) sort entirely.
Performance & readability rule: Detects the pattern of calling Enum.sort/1,2
followed by Enum.reverse/1 on the result, where the sort direction can be
statically determined.
Performance rule: Detects string concatenation with <> inside
Enum.reduce calls with an empty string initial accumulator that can
be automatically fixed.
Performance rule: Detects String.length(x) == 1 (or != 1) used to
validate that a string is a single character.
String.length/1 traverses the entire string to count grapheme clusters,
making it O(n). For a simple single-character check, pattern matching on
the result of String.graphemes/1 is more expressive and idiomatic.
This rule automatically rewrites the comparison to use match?/2 with
String.graphemes/1, which produces a clean boolean result that works
in any expression context.
Detects Enum.take_while/2 piped into length/1 or Enum.count/1,
which materializes an intermediate list only to count it.
Detects @doc, @moduledoc, and @typedoc strings that contain a
trailing \n escape sequence.
Detects function names that use a leading underscore to indicate privacy, a convention borrowed from Python that is non-idiomatic in Elixir.
Detects unless ... do ... else ... end — a style guide violation.
Detects function clauses where every argument is a wildcard and the
body does nothing but raise.
Fixes function clauses that are not grouped together.
Prefer Enum.sort(nums, :desc) |> Enum.take(n)
over Enum.sort(nums) |> Enum.take(-n).
This is about readability and intent clarity, not performance.
Performance rule: Flags Enum.reverse(list) ++ other_list.
Enum.reverse/1 creates a new list, and ++ traverses that new list
entirely to append the second. This is a 2-pass operation.
Using Enum.reverse/2 performs both actions in a single optimized pass.
Readability and Intent rule: Flags usage of Enum.drop/2 followed by Enum.take/2.
Calling Enum.drop(list, start) piped into Enum.take(length) is a verbose way
of slicing a collection. It can be confusing to read at a glance. Elixir provides
Enum.slice/3, which explicitly communicates the intent of extracting a sublist
and handles the operation cleanly.
Replaces bare-variable float coercion tricks with explicit :erlang.float/1.
Detects @doc, @moduledoc, and @typedoc strings that contain
escaped newlines (\n) and should use heredoc syntax instead.
Detects redundant is_list/1 guards on variables already bound by a
cons pattern [head | tail]).
Behaviour for pattern-level rules that detect and auto-fix anti-patterns.
Detects the common n-gram generation pipeline that converts a string
to graphemes, creates sliding window chunks of step 1, and joins them
back into strings. This pattern is automatically fixed by replacing it
with String.slice/3 which avoids intermediate list allocations.
Detects Enum.map/2 chained into Enum.join/1 or Enum.join/2,
and suggests Enum.map_join/3 instead.
Shared utilities used by all three Credence phases (Syntax, Semantic, Pattern).
Semantic phase — fixes compiler warnings and errors.
Fixes test modules that are missing use ExUnit.Case.
Fixes compiler warnings about outdented heredoc lines by re-indenting all body content to match the closing delimiter.
Behaviour for semantic-level rules that fix compiler warnings.
Fixes compiler diagnostics about undefined, private, or deprecated functions.
Fixes the common LLM hallucination where String.alphanumeric?/1 is called
as if it were a real Elixir standard library function. It is not.
Fixes compiler warnings about unused variables by adding _ prefix.
Fixes compiler warnings about underscored variables that are referenced after being set, by removing the leading underscore.
Syntax phase — fixes code that won't parse.
Fixes div and rem used as infix operators (Python // and % style).
Fixes @spec declarations where the :: return type separator is
misplaced inside the argument parentheses.
Replaces Python's % modulo operator with Elixir's rem/2.
Fixes Python-style scientific notation that is invalid in Elixir.
Removes non-Elixir access modifier keywords prepended to def/defp/defmacro/defmacrop.
Behaviour for syntax-level rules that fix code which won't parse.