separate_alias_require.ex (2212B)
1 defmodule Credo.Check.Readability.SeparateAliasRequire do 2 use Credo.Check, 3 base_priority: :low, 4 explanations: [ 5 check: """ 6 All instances of `alias` should be consecutive within a file. 7 Likewise, all instances of `require` should be consecutive within a file. 8 9 For example: 10 11 defmodule Foo do 12 require Logger 13 alias Foo.Bar 14 15 alias Foo.Baz 16 require Integer 17 18 # ... 19 end 20 21 should be changed to: 22 23 defmodule Foo do 24 require Integer 25 require Logger 26 27 alias Foo.Bar 28 alias Foo.Baz 29 30 # ... 31 end 32 33 Like all `Readability` issues, this one is not a technical concern. 34 But you can improve the odds of others reading and liking your code by making 35 it easier to follow. 36 """ 37 ] 38 39 alias Credo.Code.Block 40 41 @doc false 42 @impl true 43 def run(%SourceFile{} = source_file, params \\ []) do 44 issue_meta = IssueMeta.for(source_file, params) 45 46 Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta)) 47 end 48 49 defp traverse({:defmodule, _, _} = ast, issues, issue_meta) do 50 {_previous_calls, issues} = 51 ast 52 |> Block.calls_in_do_block() 53 |> Enum.reduce({[], issues}, fn 54 {macro_name, meta, args}, {previous_calls, issues} 55 when is_atom(macro_name) and is_list(args) -> 56 cond do 57 List.last(previous_calls) == macro_name -> 58 {previous_calls, issues} 59 60 macro_name in [:alias, :require] and Enum.member?(previous_calls, macro_name) -> 61 {previous_calls, issues ++ [issue_for(issue_meta, meta[:line], macro_name)]} 62 63 true -> 64 {previous_calls ++ [macro_name], issues} 65 end 66 67 _, memo -> 68 memo 69 end) 70 71 {ast, issues} 72 end 73 74 defp traverse(ast, issues, _issue_meta) do 75 {ast, issues} 76 end 77 78 defp issue_for(issue_meta, line_no, type) do 79 format_issue(issue_meta, message: message(type), line_no: line_no) 80 end 81 82 def message(:alias), do: "aliases should be consecutive within a file" 83 def message(:require), do: "requires should be consecutive within a file" 84 end