zf

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

double_boolean_negation.ex (2222B)


      1 defmodule Credo.Check.Refactor.DoubleBooleanNegation do
      2   use Credo.Check,
      3     base_priority: :low,
      4     tags: [:controversial],
      5     explanations: [
      6       check: """
      7       Having double negations in your code can obscure the parameter's original value.
      8 
      9           # NOT preferred
     10 
     11           !!var
     12 
     13       This will return `false` for `false` and `nil`, and `true` for anything else.
     14 
     15       At first this seems like an extra clever shorthand to cast anything truthy to
     16       `true` and anything non-truthy to `false`. But in most scenarios you want to
     17       be explicit about your input parameters (because it is easier to reason about
     18       edge-cases, code-paths and tests).
     19       Also: `nil` and `false` do mean two different things.
     20 
     21       A scenario where you want this kind of flexibility, however, is parsing
     22       external data, e.g. a third party JSON-API where a value is sometimes `null`
     23       and sometimes `false` and you want to normalize that before handing it down
     24       in your program.
     25 
     26       In these case, you would be better off making the cast explicit by introducing
     27       a helper function:
     28 
     29           # preferred
     30 
     31           defp present?(nil), do: false
     32           defp present?(false), do: false
     33           defp present?(_), do: true
     34 
     35       This makes your code more explicit than relying on the implications of `!!`.
     36       """
     37     ]
     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   # Checking for `!!`
     48   defp traverse({:!, meta, [{:!, _, ast}]}, issues, issue_meta) do
     49     issue =
     50       format_issue(
     51         issue_meta,
     52         message: "Double boolean negation found.",
     53         trigger: "!!",
     54         line_no: meta[:line]
     55       )
     56 
     57     {ast, [issue | issues]}
     58   end
     59 
     60   # Checking for `not not`
     61   defp traverse({:not, meta, [{:not, _, ast}]}, issues, issue_meta) do
     62     issue =
     63       format_issue(
     64         issue_meta,
     65         message: "Double boolean negation found.",
     66         trigger: "not not",
     67         line_no: meta[:line]
     68       )
     69 
     70     {ast, [issue | issues]}
     71   end
     72 
     73   defp traverse(ast, issues, _issue_meta) do
     74     {ast, issues}
     75   end
     76 end