zf

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

raise_inside_rescue.ex (2194B)


      1 defmodule Credo.Check.Warning.RaiseInsideRescue do
      2   use Credo.Check,
      3     explanations: [
      4       check: """
      5       Using `Kernel.raise` inside of a `rescue` block creates a new stacktrace.
      6 
      7       Most of the time, this is not what you want to do since it obscures the cause of the original error.
      8 
      9       Example:
     10 
     11           # preferred
     12 
     13           try do
     14             raise "oops"
     15           rescue
     16             error ->
     17               Logger.warn("An exception has occurred")
     18 
     19               reraise error, System.stacktrace
     20           end
     21 
     22           # NOT preferred
     23 
     24           try do
     25             raise "oops"
     26           rescue
     27             error ->
     28               Logger.warn("An exception has occurred")
     29 
     30               raise error
     31           end
     32       """
     33     ]
     34 
     35   alias Credo.Code.Block
     36 
     37   @def_ops [:def, :defp, :defmacro, :defmacrop]
     38 
     39   @doc false
     40   @impl true
     41   def run(%SourceFile{} = source_file, params) do
     42     issue_meta = IssueMeta.for(source_file, params)
     43 
     44     Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
     45   end
     46 
     47   # TODO: consider for experimental check front-loader (ast)
     48   defp traverse({:try, _meta, _arguments} = ast, issues, issue_meta) do
     49     case Block.rescue_block_for(ast) do
     50       {:ok, ast} ->
     51         issues_found = Credo.Code.prewalk(ast, &find_issues(&1, &2, issue_meta))
     52 
     53         {ast, issues ++ issues_found}
     54 
     55       _ ->
     56         {ast, issues}
     57     end
     58   end
     59 
     60   defp traverse(
     61          {op, _meta, [_def, [do: _do, rescue: rescue_block]]},
     62          issues,
     63          issue_meta
     64        )
     65        when op in @def_ops do
     66     issues_found = Credo.Code.prewalk(rescue_block, &find_issues(&1, &2, issue_meta))
     67 
     68     {rescue_block, issues ++ issues_found}
     69   end
     70 
     71   defp traverse(ast, issues, _issue_meta), do: {ast, issues}
     72 
     73   defp find_issues({:raise, meta, _arguments} = ast, issues, issue_meta) do
     74     issue = issue_for(issue_meta, meta[:line])
     75 
     76     {ast, issues ++ [issue]}
     77   end
     78 
     79   defp find_issues(ast, issues, _), do: {ast, issues}
     80 
     81   defp issue_for(issue_meta, line_no) do
     82     format_issue(
     83       issue_meta,
     84       message: "Use `reraise` inside a rescue block to preserve the original stacktrace.",
     85       trigger: "raise",
     86       line_no: line_no
     87     )
     88   end
     89 end