zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

redundant_with_clause_result.ex (2459B)


      1 defmodule Credo.Check.Refactor.RedundantWithClauseResult do
      2   use Credo.Check,
      3     base_priority: :high,
      4     explanations: [
      5       check: ~S"""
      6       `with` statements are useful when you need to chain a sequence
      7       of pattern matches, stopping at the first one that fails.
      8 
      9       If the match of the last clause in a `with` statement is identical to the expression in the
     10       in its body, the code should be refactored to remove the redundant expression.
     11 
     12       This should be refactored:
     13 
     14           with {:ok, map} <- check(input),
     15                {:ok, result} <- something(map) do
     16             {:ok, result}
     17           end
     18 
     19       to look like this:
     20 
     21           with {:ok, map} <- check(input) do
     22             something(map)
     23           end
     24       """
     25     ]
     26 
     27   alias Credo.Code.Block
     28 
     29   require Logger
     30 
     31   @redundant_with "the `with` statement is redundant"
     32   @redundant_clause "the last clause in `with` is redundant"
     33 
     34   @doc false
     35   @impl true
     36   def run(%SourceFile{} = source_file, params) do
     37     issue_meta = IssueMeta.for(source_file, params)
     38     Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
     39   end
     40 
     41   defp traverse({:with, meta, clauses_and_body} = ast, issues, issue_meta) do
     42     case split(clauses_and_body) do
     43       {:ok, clauses, body} ->
     44         case issue_for({clauses, body}, meta, issue_meta) do
     45           nil -> {ast, issues}
     46           issue -> {ast, [issue | issues]}
     47         end
     48 
     49       :error ->
     50         {ast, issues}
     51     end
     52   end
     53 
     54   defp traverse(ast, issues, _issue_meta) do
     55     {ast, issues}
     56   end
     57 
     58   defp split(clauses_and_body) do
     59     case Block.do_block?(clauses_and_body) and not Block.else_block?(clauses_and_body) do
     60       false ->
     61         :error
     62 
     63       true ->
     64         {clauses, [body]} = Enum.split(clauses_and_body, -1)
     65         {:ok, clauses, Keyword.get(body, :do)}
     66     end
     67   end
     68 
     69   defp issue_for({clauses, body}, meta, issue_meta) do
     70     case {redundant?(List.last(clauses), body), length(clauses)} do
     71       {true, 1} ->
     72         format_issue(issue_meta, message: @redundant_with, line_no: meta[:line])
     73 
     74       {true, _length} ->
     75         format_issue(issue_meta, message: @redundant_clause, line_no: meta[:line])
     76 
     77       _else ->
     78         nil
     79     end
     80   end
     81 
     82   defp redundant?({:<-, _meta, [body, _expr]}, body), do: true
     83 
     84   defp redundant?({:<-, _meta, [match, _expr]}, body) do
     85     Credo.Code.remove_metadata(match) == Credo.Code.remove_metadata(body)
     86   end
     87 
     88   defp redundant?(_last_clause, _body), do: false
     89 end