Current section
Files
Jump to
Current section
Files
README.md
# Smell
[Credo](https://github.com/rrrene/credo) checks for the
[anti-patterns described in the official Elixir documentation](https://hexdocs.pm/elixir/what-anti-patterns.html).
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`:
```elixir
def deps do
[
{:smell, "~> 0.2", only: [:dev, :test], runtime: false}
]
end
```
Then enable the plugin in your `.credo.exs`:
```elixir
%{
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:
```elixir
checks: %{
enabled:
[
# ...your existing checks...
] ++ Enum.map(Smell.checks(), &{&1, []})
}
```
## Checks
| Check | Anti-pattern | Reports |
| --- | --- | --- |
| `Smell.Check.Design.AppConfigInLibrary` | [Using application configuration for libraries](https://hexdocs.pm/elixir/design-anti-patterns.html#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`](https://hexdocs.pm/elixir/macro-anti-patterns.html#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`](https://hexdocs.pm/elixir/code-anti-patterns.html#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](https://hexdocs.pm/elixir/code-anti-patterns.html#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](https://hexdocs.pm/elixir/code-anti-patterns.html#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`:
- `library` (default `:auto`): `:auto` checks the project when its `mix.exs` has
a `:package` and no `:releases`; `true` always checks it, `false` never does.
- `allowed_keys` (default `[]`): keys the library may read, as atoms or regexes,
for example settings used to generate code from data files:
`[:statuses, ~r/^debug_/]`. For a key path such as `[MyLib.Repo, :timeout]`,
the last key is matched.
- `exclude_test_files` (default `true`): skip files under `test/`.
```elixir
{Smell.Check.Design.AppConfigInLibrary, [allowed_keys: [:statuses]]}
```
`UseInsteadOfImport`:
- `exclude_test_files` (default `true`): skip files under `test/`.
`ComplexElseClauses`:
- `max_else_clauses` (default `1`): the maximum number of clauses allowed in the
`else` block.
`NamespaceTrespassing`:
- `allowed_namespaces` (default `[]`): namespaces the project may define modules
in, for example when you maintain both packages: `[Phoenix.LiveView]`.
- `lockfile` (default `"mix.lock"`): where to read dependencies from, relative to
where Credo runs.
- `exclude_test_files` (default `true`): skip files under `test/`.
```elixir
{Smell.Check.Warning.NamespaceTrespassing, [allowed_namespaces: [Phoenix.LiveView]]}
```
`NonAssertivePatternMatching`:
- `exclude_test_files` (default `true`): skip files under `test/`.
### 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](https://github.com/RicardoSantos-99/smell/blob/master/LICENSE).