API Reference credence v#0.6.0

Copy Markdown

Modules

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.

Readability & performance rule: Detects multiple Enum.at/2 calls on the same variable with literal indices. Each Enum.at/2 traverses the list from the head, so N calls cost O(N × len). Pattern matching destructures the list in a single pass.

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.