From da73a61bb01ae4d67e3fadc7721c98026fdf81dd Mon Sep 17 00:00:00 2001 From: Andrew Summers Date: Fri, 22 Mar 2019 18:18:13 -0500 Subject: [PATCH] Add multi-alias expansion warning. --- .credo.exs | 1 + lib/credo/check/readability/multi_alias.ex | 61 +++++++++++++++++++ .../check/readability/multi_alias_test.exs | 44 +++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 lib/credo/check/readability/multi_alias.ex create mode 100644 test/credo/check/readability/multi_alias_test.exs diff --git a/.credo.exs b/.credo.exs index 3b040c586..63d6acd5b 100644 --- a/.credo.exs +++ b/.credo.exs @@ -141,6 +141,7 @@ # {Credo.Check.Consistency.MultiAliasImportRequireUse, false}, {Credo.Check.Design.DuplicatedCode, false}, + {Credo.Check.Readability.MultiAlias, false}, {Credo.Check.Readability.Specs, false}, {Credo.Check.Refactor.ABCSize, false}, {Credo.Check.Refactor.AppendSingleItem, false}, diff --git a/lib/credo/check/readability/multi_alias.ex b/lib/credo/check/readability/multi_alias.ex new file mode 100644 index 000000000..4a7113a33 --- /dev/null +++ b/lib/credo/check/readability/multi_alias.ex @@ -0,0 +1,61 @@ +defmodule Credo.Check.Readability.MultiAlias do + @moduledoc false + + @checkdoc """ + Multi alias expansion makes module uses harder to search for in large code bases. + + # preferred + + alias Module.Foo + alias Module.Bar + + # NOT preferred + + alias Module.{Foo, Bar} + + Like all `Readability` issues, this one is not a technical concern. + But you can improve the odds of others reading and liking your code by making + it easier to follow. + """ + @explanation [check: @checkdoc] + + use Credo.Check, base_priority: :low + + alias Credo.Code + + @doc false + def run(source_file, params \\ []) do + issue_meta = IssueMeta.for(source_file, params) + + Code.prewalk(source_file, &traverse(&1, &2, issue_meta)) + end + + defp traverse( + {:alias, _, [{{_, _, [{:__aliases__, opts, base_alias}, :{}]}, _, [multi_alias | _]}]} = + ast, + issues, + issue_meta + ) do + {:__aliases__, _, [module | []]} = multi_alias + new_issue = issue_for(issue_meta, Keyword.get(opts, :line), base_alias, module) + + {ast, [new_issue | issues]} + end + + defp traverse(ast, issues, _issue_meta), do: {ast, issues} + + defp issue_for(issue_meta, line_no, base_alias, trigger) do + module = + base_alias + |> Kernel.++([trigger]) + |> Module.concat() + |> inspect() + + format_issue( + issue_meta, + message: "Avoid multi aliases to #{module}; consider removing.", + trigger: trigger, + line_no: line_no + ) + end +end diff --git a/test/credo/check/readability/multi_alias_test.exs b/test/credo/check/readability/multi_alias_test.exs new file mode 100644 index 000000000..a35104742 --- /dev/null +++ b/test/credo/check/readability/multi_alias_test.exs @@ -0,0 +1,44 @@ +defmodule Credo.Check.Readability.MultiAliasTest do + use Credo.TestHelper + + @described_check Credo.Check.Readability.MultiAlias + + # + # cases NOT raising issues + # + + test "it should NOT report violation" do + """ + defmodule Test do + alias App.Module1 + alias App.Module2 + end + """ + |> to_source_file + |> refute_issues(@described_check) + end + + # + # cases raising issues + # + + test "it should report a violation" do + """ + defmodule CredoSampleModule do + alias App.Module2.{Module3} + end + """ + |> to_source_file + |> assert_issue(@described_check) + end + + test "it should report a violation for multiple expansions" do + """ + defmodule CredoSampleModule do + alias App.{Module1, Module2} + end + """ + |> to_source_file + |> assert_issue(@described_check) + end +end