Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save paulo-ferraz-oliveira/f80993b108d402a8528d0e27764c5116 to your computer and use it in GitHub Desktop.
Save paulo-ferraz-oliveira/f80993b108d402a8528d0e27764c5116 to your computer and use it in GitHub Desktop.
An Elixir Credo custom check for making sure you don't have duplicate `use`

Here's an example on how to do it.

defmodule OneUseAlone do
  use Credo.Check,
    base_priority: :high,
    category: :warning,
    explanations: [
      check: """
      Checks if `use` happens more than once in a given module
      """
    ]

  @impl Credo.Check
  def run(source_file, params) do
    issue_meta = Credo.IssueMeta.for(source_file, params)

    Credo.Code.prewalk(source_file, &walk(&1, &2, issue_meta))
  end

  defp walk(ast, issues, issue_meta) do
    case(ast) do
      {:defmodule, _meta, _children} ->
        new_issues =
          ast
          |> Credo.Code.prewalk(&collect/2)
          |> report(issue_meta)

        {ast, issues ++ new_issues}

      _other ->
        {ast, issues}
    end
  end

  defp collect(ast, acc) do
    case(ast) do
      {:use, _meta, [{:__aliases__, meta, module}]} ->
        {ast, acc ++ [{module, meta[:line]}]}

      # Reset on submodules
      {:defmodule, _meta, _children} when length(acc) < 2 ->
        {ast, []}

      _other ->
        {ast, acc}
    end
  end

  defp report(uses, issue_meta) do
    if length(uses) < 2 do
      []
    else
      [
        format_issue(
          issue_meta,
          message: "`use ...` appears more than once in the module"
        )
      ]
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment