-
Notifications
You must be signed in to change notification settings - Fork 414
/
forbidden_module.ex
71 lines (57 loc) · 2.18 KB
/
forbidden_module.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
defmodule Credo.Check.Warning.ForbiddenModule do
use Credo.Check,
base_priority: :high,
category: :warning,
param_defaults: [modules: []],
explanations: [
check: """
Some modules that are included by a package may be hazardous
if used by your application. Use this check to allow these modules in
your dependencies but forbid them to be used in your application.
Examples:
The `:ecto_sql` package includes the `Ecto.Adapters.SQL` module,
but direct usage of the `Ecto.Adapters.SQL.query/4` function, and related functions, may
cause issues when using Ecto's dynamic repositories.
""",
params: [modules: "List of Modules or {Module, \"Error message\"} Tuples that must not be used."]
]
alias Credo.Code
@impl Credo.Check
def run(source_file = %SourceFile{}, params) do
modules = Params.get(params, :modules, __MODULE__)
Code.prewalk(source_file, &traverse(&1, &2, modules, IssueMeta.for(source_file, params)))
end
defp traverse(ast = {:__aliases__, meta, modules}, issues, modules_param, issue_meta) do
module = Module.concat(modules)
forbidden_modules =
if Keyword.keyword?(modules_param), do: Keyword.keys(modules_param), else: modules_param
if found_module?(forbidden_modules, module) do
{ast, [issue_for(issue_meta, meta[:line], module, modules_param) | issues]}
else
{ast, issues}
end
end
defp traverse(ast, issues, _, _), do: {ast, issues}
defp found_module?(forbidden_modules, module)
when is_list(forbidden_modules) and is_atom(module) do
Enum.member?(forbidden_modules, module)
end
defp found_module?(_, _), do: false
defp issue_for(issue_meta, line_no, module, modules_param) do
trigger = module |> Code.Module.name()
format_issue(
issue_meta,
message: message(modules_param, module, "The `#{trigger}` module is not allowed."),
trigger: trigger,
line_no: line_no
)
end
defp message(modules_param, module, default) do
with true <- Keyword.keyword?(modules_param),
value when not is_nil(value) <- Keyword.get(modules_param, module) do
value
else
_ -> default
end
end
end