Credence.Pattern.PreferNoQuestionMarkForNonBoolean (credence v0.8.0)

Copy Markdown

Detects functions with a ? suffix whose @spec declares a non-boolean return type and renames them to drop the suffix.

In Elixir, the ? suffix conventionally indicates a boolean predicate (returns true or false). A function with a @spec returning integer() | nil, String.t(), or any other non-boolean type should not use the ? suffix.

Only private (defp) functions are flagged. Renaming a public def is a breaking API change for callers in other modules, and the rename can't reach @doc/c:Mod.fun?/n references outside the analysed AST; a ? on a public function is also often a deliberate mirror of a wrapped boolean API. So the rule cleans up only private helpers, whose every call site lives in-module.

Bad

@spec find_max_integer?([any()]) :: integer() | nil
defp find_max_integer?([]), do: nil
defp find_max_integer?(list) when is_list(list) do
  if Enum.any?(list, fn element -> not is_integer(element) end) do
    nil
  else
    Enum.max(list)
  end
end

Good

@spec find_max_integer([any()]) :: integer() | nil
defp find_max_integer([]), do: nil
defp find_max_integer(list) when is_list(list) do
  if Enum.any?(list, fn element -> not is_integer(element) end) do
    nil
  else
    Enum.max(list)
  end
end

Auto-fix

Renames all occurrences of the flagged private function (in @spec, defp, and in-module call sites) to the name without the ? suffix.