Skip to content
Permalink
Browse files

Merge pull request #652 from liskin/fix-aliases-in-duplicated-code

Fix DuplicatedCode not matching blocks with external calls
  • Loading branch information...
rrrene committed May 3, 2019
2 parents c10e6ba + 702c6d0 commit bb4da3187d910f526120884265dc0e9df295371a
Showing with 50 additions and 44 deletions.
  1. +1 −44 lib/credo/code.ex
  2. +31 −0 test/credo/check/design/duplicated_code_test.exs
  3. +18 −0 test/credo/code_test.exs
@@ -196,50 +196,7 @@ defmodule Credo.Code do
@doc """
Returns an AST without its metadata.
"""
def remove_metadata(ast) when is_tuple(ast) do
update_metadata(ast, fn _ast -> [] end)
end

def remove_metadata(ast) do
ast
|> List.wrap()
|> Enum.map(&update_metadata(&1, fn _ast -> [] end))
end

defp update_metadata({atom, _meta, list} = ast, fun) when is_list(list) do
{atom, fun.(ast), Enum.map(list, &update_metadata(&1, fun))}
end

defp update_metadata([do: tuple], fun) when is_tuple(tuple) do
[do: update_metadata(tuple, fun)]
end

defp update_metadata([do: tuple, else: tuple2], fun) when is_tuple(tuple) do
[do: update_metadata(tuple, fun), else: update_metadata(tuple2, fun)]
end

defp update_metadata({:do, tuple}, fun) when is_tuple(tuple) do
{:do, update_metadata(tuple, fun)}
end

defp update_metadata({:else, tuple}, fun) when is_tuple(tuple) do
{:else, update_metadata(tuple, fun)}
end

defp update_metadata({atom, _meta, arguments} = ast, fun) do
{atom, fun.(ast), arguments}
Macro.prewalk(ast, &Macro.update_meta(&1, fn _meta -> [] end))
end

defp update_metadata(v, fun) when is_list(v), do: Enum.map(v, &update_metadata(&1, fun))

defp update_metadata(tuple, fun) when is_tuple(tuple) do
tuple
|> Tuple.to_list()
|> Enum.map(&update_metadata(&1, fun))
|> List.to_tuple()
end

defp update_metadata(v, _fun)
when is_atom(v) or is_binary(v) or is_float(v) or is_integer(v),
do: v
end
@@ -75,6 +75,37 @@ defmodule Credo.Check.Design.DuplicatedCodeTest do
|> assert_issues(@described_check, mass_threshold: 16)
end

test "should raise an issue for duplicated code with different line numbers and external function call" do
s1 = """
defmodule M1 do
def myfun(p1, p2) when is_list(p2) do
if p1 == p2 do
A.f(p1)
else
p2 + p1
end
end
end
"""

s2 = """
defmodule M2 do
# additional line here
def myfun(p1, p2) when is_list(p2) do
if p1 == p2 do
A.f(p1)
else
p2 + p1
end
end
end
"""

[s1, s2]
|> to_source_files
|> assert_issues(@described_check, mass_threshold: 16)
end

test "should NOT raise an issue for duplicated code via macros if macros are in :excluded_macros param" do
s1 = """
defmodule M1 do
@@ -363,4 +363,22 @@ defmodule Credo.CodeTest do

assert expected == Credo.Code.remove_metadata(ast)
end

test "returns ast with external call without metadata" do
ast =
{{:., [line: 1, column: 7],
[
{:__aliases__, [line: 1, column: 1], [:Kernel]},
:node
]}, [line: 1, column: 7], []}

expected =
{{:., [],
[
{:__aliases__, [], [:Kernel]},
:node
]}, [], []}

assert expected == Credo.Code.remove_metadata(ast)
end
end

0 comments on commit bb4da31

Please sign in to comment.
You can’t perform that action at this time.