From bb54b0fee2ace9fd4c463363e2dba59a9a9b5f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20F=C3=B6hring?= Date: Sun, 15 Dec 2024 22:15:14 +0100 Subject: [PATCH] Fix false negative for ModuleDoc Refs #1168 --- lib/credo/code/module.ex | 19 +++++++++++++++ test/credo/code/module_test.exs | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/lib/credo/code/module.ex b/lib/credo/code/module.ex index 9be7c2ccf..ba16c7160 100644 --- a/lib/credo/code/module.ex +++ b/lib/credo/code/module.ex @@ -74,6 +74,25 @@ defmodule Credo.Code.Module do end @doc "Reads an attribute from a module's `ast`" + def attribute({:defmodule, _, _arguments} = ast, attr_name) do + arguments = + case Credo.Code.Block.do_block_for!(ast) do + {:__block__, [], arguments} -> arguments + value -> List.wrap(value) + end + + attr_value = + Enum.find_value(arguments, fn + {:@, _meta, [{^attr_name, _, [value]} | _tail]} -> {:ok, value} + _ -> nil + end) + + case attr_value do + {:ok, value} -> value + error -> {:error, error} + end + end + def attribute(ast, attr_name) do case Credo.Code.postwalk(ast, &find_attribute(&1, &2, attr_name), {:error, nil}) do {:ok, value} -> diff --git a/test/credo/code/module_test.exs b/test/credo/code/module_test.exs index 06620d80c..d0c15080c 100644 --- a/test/credo/code/module_test.exs +++ b/test/credo/code/module_test.exs @@ -28,6 +28,47 @@ defmodule Credo.Code.ModuleTest do assert false == Module.attribute(ast, :moduledoc) end + test "should return the given module attribute for the top module in the given AST" do + {:ok, ast} = + """ + defmodule CredoExample do + @attr_list [:atom1, :atom2] + @attr_string "This is a String" + @attr_number 42 + + @moduledoc false + + defmodule Foo do + @attr_list [:atom3, :atom4] + @attr_string "This is another String" + @attr_number -1 + + @moduledoc "test" + end + end + """ + |> Code.string_to_quoted() + + assert [:atom1, :atom2] == Module.attribute(ast, :attr_list) + assert "This is a String" == Module.attribute(ast, :attr_string) + assert 42 == Module.attribute(ast, :attr_number) + assert false == Module.attribute(ast, :moduledoc) + end + + test "should return the given module attribute, if found" do + ast = + {:defmodule, [line: 2, column: 3], + [ + {:__aliases__, [line: 2, column: 13], [:SubModule]}, + [do: {:__block__, [], []}] + ]} + + assert {:error, nil} == Module.attribute(ast, :attr_list) + assert {:error, nil} == Module.attribute(ast, :attr_string) + assert {:error, nil} == Module.attribute(ast, :attr_number) + assert {:error, nil} == Module.attribute(ast, :moduledoc) + end + # # def_count #