zf

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

application_config_in_module_attribute.ex (2981B)


      1 defmodule Credo.Check.Warning.ApplicationConfigInModuleAttribute do
      2   use Credo.Check,
      3     base_priority: :high,
      4     tags: [:controversial],
      5     category: :warning,
      6     explanations: [
      7       check: """
      8       Module attributes are evaluated at compile time and not at run time. As
      9       a result, certain configuration read calls made in your module attributes
     10       may work as expected during local development, but may break once in a
     11       deployed context.
     12 
     13       This check analyzes all of the module attributes present within a module,
     14       and validates that there are no unsafe calls.
     15 
     16       These unsafe calls include:
     17 
     18       - `Application.fetch_env/2`
     19       - `Application.fetch_env!/2`
     20       - `Application.get_all_env/1`
     21       - `Application.get_env/3`
     22       - `Application.get_env/2`
     23 
     24       As of Elixir 1.10 you can leverage `Application.compile_env/3` and
     25       `Application.compile_env!/2` if you wish to set configuration at
     26       compile time using module attributes.
     27       """
     28     ]
     29 
     30   @doc false
     31   @impl true
     32   def run(%SourceFile{} = source_file, params \\ []) do
     33     issue_meta = IssueMeta.for(source_file, params)
     34 
     35     Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
     36   end
     37 
     38   defp traverse({:@, meta, [attribute_definition]} = ast, issues, issue_meta) do
     39     case traverse_attribute(attribute_definition) do
     40       nil ->
     41         {ast, issues}
     42 
     43       {attribute, call} ->
     44         {ast, issues_for_call(attribute, call, meta, issue_meta, issues)}
     45     end
     46   end
     47 
     48   defp traverse(ast, issues, _issue_meta) do
     49     {ast, issues}
     50   end
     51 
     52   defp traverse_attribute({attribute, _, _} = ast) do
     53     case Macro.prewalk(ast, nil, &get_forbidden_call/2) do
     54       {_ast, nil} ->
     55         nil
     56 
     57       {_ast, call} ->
     58         {attribute, call}
     59     end
     60   end
     61 
     62   defp traverse_attribute(_ast) do
     63     nil
     64   end
     65 
     66   defp get_forbidden_call(
     67          {{:., _, [{:__aliases__, _, [:Application]}, :fetch_env]}, _meta, _args} = ast,
     68          _acc
     69        ) do
     70     {ast, "Application.fetch_env/2"}
     71   end
     72 
     73   defp get_forbidden_call(
     74          {{:., _, [{:__aliases__, _, [:Application]}, :fetch_env!]}, _meta, _args} = ast,
     75          _acc
     76        ) do
     77     {ast, "Application.fetch_env!/2"}
     78   end
     79 
     80   defp get_forbidden_call(
     81          {{:., _, [{:__aliases__, _, [:Application]}, :get_all_env]}, _meta, _args} = ast,
     82          _acc
     83        ) do
     84     {ast, "Application.get_all_env/1"}
     85   end
     86 
     87   defp get_forbidden_call(
     88          {{:., _, [{:__aliases__, _, [:Application]}, :get_env]}, _meta, args} = ast,
     89          _acc
     90        ) do
     91     {ast, "Application.get_env/#{length(args)}"}
     92   end
     93 
     94   defp get_forbidden_call(ast, acc) do
     95     {ast, acc}
     96   end
     97 
     98   defp issues_for_call(attribute, call, meta, issue_meta, issues) do
     99     options = [
    100       message:
    101         "Module attribute @#{Atom.to_string(attribute)} makes use of unsafe Application configuration call #{call}",
    102       trigger: call,
    103       line_no: meta[:line]
    104     ]
    105 
    106     [format_issue(issue_meta, options) | issues]
    107   end
    108 end