Smell

Credo checks for the anti-patterns described in the official Elixir documentation.

The catalog comes from the research of Lucas Vegi and Marco Tulio Valente (ASERG/DCC/UFMG). Smell turns the anti-patterns that can be found by static analysis into Credo checks, and links each check to the matching section of the documentation.

Installation

Add smell to your dependencies in mix.exs:

def deps do
  [
    {:smell, "~> 0.2", only: [:dev, :test], runtime: false}
  ]
end

Then enable the plugin in your .credo.exs:

%{
  configs: [
    %{
      name: "default",
      plugins: [{Smell, []}]
    }
  ]
}

If your .credo.exs declares an explicit checks: %{enabled: [...]} list (as the one generated by mix credo.gen.config does), Credo only runs the checks in that list. Add Smell's checks to it:

checks: %{
  enabled:
    [
      # ...your existing checks...
    ] ++ Enum.map(Smell.checks(), &{&1, []})
}

Checks

Check Anti-pattern Reports
Smell.Check.Design.AppConfigInLibrary Using application configuration for libraries In a library (a mix.exs with :package and no :releases), a read of the library's own application environment (Application.get_env/3, fetch_env!/2, compile_env/3, ...), except keys that swap a component (:adapter, :json_library, ...) and the :otp_app pattern
Smell.Check.Design.UseInsteadOfImport use instead of import A __using__/1 whose clauses only inject import, alias and require directives (unless it is deprecated)
Smell.Check.Readability.ComplexElseClauses Complex else clauses in with A with with two or more <- clauses whose else block has more than max_else_clauses (default 1) clauses
Smell.Check.Warning.NamespaceTrespassing Namespace trespassing A top-level module defined inside a namespace owned by Elixir (Mix, Logger, ...) or by a dependency listed in mix.lock (Plug, Phoenix, ...)
Smell.Check.Warning.NonAssertivePatternMatching Non-assertive pattern matching A case that matches {:ok, value} and then everything else with _, with no clause for :error or {:error, ...}

Run mix credo explain on an issue to see the full explanation and the parameters of each check.

Parameters

AppConfigInLibrary:

{Smell.Check.Design.AppConfigInLibrary, [allowed_keys: [:statuses]]}

UseInsteadOfImport:

ComplexElseClauses:

NamespaceTrespassing:

{Smell.Check.Warning.NamespaceTrespassing, [allowed_namespaces: [Phoenix.LiveView]]}

NonAssertivePatternMatching:

Anti-patterns Credo already covers

Some anti-patterns from the documentation already have a check in Credo itself, so Smell does not duplicate them:

Anti-pattern Credo check
Dynamic atom creation Credo.Check.Warning.UnsafeToAtom
Long parameter list Credo.Check.Refactor.FunctionArity
Structs with 32 fields or more Credo.Check.Warning.StructFieldAmount (Credo 1.7.14+)
with with a single <- clause and an else Credo.Check.Readability.WithSingleClause

License

MIT. See LICENSE.