【问题标题】:Finding functions using specific macro使用特定宏查找函数
【发布时间】:2021-07-05 02:14:41
【问题描述】:

有没有一种方法可以找到使用我创建的特定宏列出的所有函数?我在想可以使用:application.get_key 函数找到它们。

类似的东西

defmodule DefFooModule do
  defmacro deffoo(head, body) do
    quote do
      def unquote(head) do
        unquote(body[:do])
      end
    end
  end

  def find_all_foos do
    {:ok, modules} = :application.get_key(:app, :modules)
    ## something here???
    ## output [
    ##  AnotherModule.do_something/0, 
    ##  AnotherModule.do_something_else/0, 
    ##  AnotherModule2.do_something_2/0
    ## ]
  end
end

defmodule AnotherModule do
  deffoo do_something do
    ## function goes in here
  end
  deffoo do_something_else do
    ## function goes in here
  end
end
defmodule AnotherModule2 do
  deffoo do_something_2 do
    ## function goes in here
  end
end

谢谢

【问题讨论】:

    标签: module macros attributes elixir metaprogramming


    【解决方案1】:

    您可以使用mix xref 任务列出模块的调用者,但不能列出特定宏/函数的调用者。如果您在模块中只定义了这个宏,您可以尝试使用mix xref callers MyModule

    我可以建议一个仅适用于跟踪宏调用的自定义解决方案。您需要运行 OTP 21.2 或更高版本才能使用 :persistent_term。如果您使用的是旧 OTP 版本,:persistent_term 可以替换为 ETS,但逻辑相同。

    defmodule T do
      defmacro foo() do
        callers = :persistent_term.get(:macro_callers, [])
    
        file_line = __CALLER__.file <> ":#{__CALLER__.line}"
        caller_info = {file_line, __CALLER__.module, __CALLER__.function}
    
        :persistent_term.put(:macro_callers, [ caller_info | callers])
    
        quote do
          1 + 2
        end
      end
    
      def get_callers(), do: :persistent_term.get(:macro_callers, [])
    end
    
    defmodule T2 do
      require T
      def bar(), do: T.foo()
    end
    
    
    defmodule T3 do
      require T
      def baz(), do: T.foo()
    end
    
    defmodule T4 do
      require T
      def boo(), do: T.foo()
    end
    

    如果在宏的quote 块之外添加一些代码,则在编译过程中处理宏时会执行一次。它可以访问返回当前调用环境的__CALLER__ 宏。调用__CALLER__ 的结果是一个Macro.Env 结构。在此特定示例中,此代码将调用者的文件、行、模块、函数名称和函数数量存储在 :persistent_term 中,以便您以后检索它。

    编译完所有模块编译后在运行时执行T.get_callers返回如下结果:

    [
      {"/Users/ivan/macro_callers.ex:31", T4, {:boo, 0}},
      {"/Users/ivan/macro_callers.ex:26", T3, {:baz, 0}},
      {"/Users/ivan/macro_callers.ex:20", T2, {:bar, 0}}
    ]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多