Credence.Pattern.NoGraphemePalindrome
(credence v0.7.1)
Copy Markdown
Readability & performance rule: Detects the pattern of decomposing a string
into graphemes, only to compare it with its own Enum.reverse.
This pattern creates an unnecessary intermediate list. Use String.reverse/1
and compare strings directly instead.
Only the String.graphemes/1 form is handled — both it and String.reverse/1
operate in grapheme space, so the rewrite is behaviour-identical for every
input. The superficially similar String.to_charlist/1 form is deliberately
not rewritten: charlists index codepoints, while String.reverse/1
reverses graphemes, and the two diverge on multi-codepoint graphemes
(decomposed accents, ZWJ emoji, flags). See the codepoint↔grapheme policy in
CONTEXT.md.
What is flagged / fixed
The fix shape depends on what the decomposed variable was built from and whether it is used anywhere besides the palindrome comparison:
- built from a bare variable, used only in the comparison →
the original string is inlined and the binding dropped:
g = String.graphemes(s); g == Enum.reverse(g)→s == String.reverse(s) - built from a bare variable, but used elsewhere as a grapheme list →
the comparison is inlined to
s == String.reverse(s)while theString.graphemes/1binding is kept intact (so the other uses still see a list — rebinding it to the raw string would change their behaviour). - built from a larger expression (e.g. a pipe), used only in the
comparison → the terminal
String.graphemes/1is stripped from the binding and the comparison uses the variable:g = s |> f() |> String.graphemes(); g == Enum.reverse(g)→g = s |> f(); g == String.reverse(g)(inlining would duplicatef). - built from a larger expression and used elsewhere → not flagged: there is no behaviour-preserving single-expression rewrite.
Bad
graphemes = String.graphemes(s)
graphemes == Enum.reverse(graphemes)
normalized = s |> String.downcase() |> String.graphemes()
normalized == Enum.reverse(normalized)Good
s == String.reverse(s)
normalized = s |> String.downcase()
normalized == String.reverse(normalized)