lib/credo/check/readability/impl_true.ex

defmodule Credo.Check.Readability.ImplTrue do
  use Credo.Check,
    base_priority: :normal,
    explanations: [
      check: """
      When implementing behaviour callbacks, `@impl true` indicates that a function implements a callback, but
      a better way is to note the actual behaviour being implemented, for example `@impl MyBehaviour`. This
      not only improves readability, but adds extra validation in cases where multiple behaviours are implemented
      in a single module.

      Instead of:

          @impl true
          def my_funcion() do
            ...

      use:

          @impl MyBehaviour
          def my_funcion() do
            ...

      """
    ]

  alias Credo.Code.Heredocs

  @doc false
  @impl true
  def run(%SourceFile{} = source_file, params) do
    issue_meta = IssueMeta.for(source_file, params)

    source_file
    |> Heredocs.replace_with_spaces()
    |> String.split("\n")
    |> Enum.with_index(1)
    |> Enum.reduce([], &check_line(&1, &2, issue_meta))
  end

  defp check_line({line, line_number}, issues, issue_meta) do
    case String.trim(line) do
      "@impl true" -> [issue_for(issue_meta, line_number) | issues]
      _ -> issues
    end
  end

  defp issue_for(issue_meta, line_no) do
    format_issue(
      issue_meta,
      message: "@impl true should be @impl MyBehaviour",
      trigger: "@impl true",
      line_no: line_no
    )
  end
end