collector.ex (1933B)
1 defmodule Credo.Check.Consistency.ExceptionNames.Collector do 2 @moduledoc false 3 4 use Credo.Check.Consistency.Collector 5 6 alias Credo.Code.Module 7 alias Credo.Code.Name 8 9 def collect_matches(source_file, _params) do 10 exception_recorder = &record_exception/2 11 12 Credo.Code.prewalk(source_file, &traverse(exception_recorder, &1, &2), %{}) 13 end 14 15 def find_locations_not_matching(expected, source_file) do 16 location_recorder = &record_not_matching(expected, &1, &2) 17 18 source_file 19 |> Credo.Code.prewalk(&traverse(location_recorder, &1, &2), []) 20 |> Enum.reverse() 21 end 22 23 defp traverse( 24 callback, 25 {:defmodule, _meta, [{:__aliases__, _, _name_arr}, _arguments]} = ast, 26 acc 27 ) do 28 if Module.exception?(ast) do 29 {ast, callback.(ast, acc)} 30 else 31 {ast, acc} 32 end 33 end 34 35 defp traverse(_callback, ast, acc), do: {ast, acc} 36 37 defp record_exception(ast, acc) do 38 {prefix, suffix} = ast |> Module.name() |> prefix_and_suffix 39 40 acc 41 |> Map.update({:prefix, prefix}, 1, &(&1 + 1)) 42 |> Map.update({:suffix, suffix}, 1, &(&1 + 1)) 43 end 44 45 defp record_not_matching(expected, {_, meta, _} = ast, acc) do 46 exception_name = Module.name(ast) 47 {prefix, suffix} = prefix_and_suffix(exception_name) 48 49 # TODO: how is this `case` necessary 50 case expected do 51 {:prefix, expected_prefix} -> 52 if prefix != expected_prefix do 53 [[line_no: meta[:line], trigger: exception_name] | acc] 54 else 55 acc 56 end 57 58 {:suffix, expected_suffix} -> 59 if suffix != expected_suffix do 60 [[line_no: meta[:line], trigger: exception_name] | acc] 61 else 62 acc 63 end 64 end 65 end 66 67 defp prefix_and_suffix(exception_name) do 68 name_list = exception_name |> Name.last() |> Name.split_pascal_case() 69 prefix = List.first(name_list) 70 suffix = List.last(name_list) 71 72 {prefix, suffix} 73 end 74 end