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