Attributes with function name

Can you use custom attributes similar to @impl or @behaviour, but rather than using a callback function, only the function name is used (e.g. @description Mod.fun).

# A.ex
defmodule A do
  use C

  @description1 "function11 returns :ok"
  def function1(_a) do
    :ok
  end

  @description2 A.function1
  def function2(_b) do
    :ok
  end
end

In the example above, the @description1 attribute is valid, since what follows is a string. Then, in @description2 fails since it tries to get a value, but instead I wish to get the name of the method (i.e. A.function1).

defmodule B do
  @behaviour Bar
  @callback foo
end

Some elixir modules are able to do something similar. For example, you can set modules/methods to @behaviour and @callback. Can something similar be created?
Thanks.

You could use a function reference there, like

@description &A.function1/1

But I’m wondering what you want to do with it? Obviously module A would then need to be compiled first.

You can capture a function with & in a module attribute:

defmodule Blergh do
  @some_attr &Blergh.foo/1
  def read_some_attr, do: @some_attr

  def foo(arg), do: IO.inspect(arg)
end

iex(2)> Blergh.read_some_attr.("hello world")
"hello world"
"hello world"

Note that the name must include the module - just spelling it foo/1 will return a CompileError.

I’m developing static checker, so all modules need to be compiled first, before analysed.

For example, the @description attribute can either be set to a string, or otherwise refer to another function (which I can process later on).

# A.ex
defmodule A do
  use B

  @description "function1/0 returns :ok"
  def function1() do
    :ok
  end

  @description A.function1
  def function2() do
    :ok
  end
end
# B.ex
defmodule B do
  defmacro __using__(_) do
    quote do
      import B
      Module.register_attribute(__MODULE__, :description, accumulate: true, persist: true)
      Module.register_attribute(__MODULE__, :test, accumulate: true, persist: true)
      @after_compile B
    end
  end

  def __on_definition__(env, _access, name, args, _guards, _body) do
    IO.puts("Reached on_definition")
    desc = Module.get_attribute(env.module, :description) |> hd()
    Module.delete_attribute(env.module, :description)
    Module.put_attribute(env.module, :test, {name, length(args), desc})
  end

  def __after_compile__(_env, bytecode) do
    IO.puts("Reached after_compile")
    # Gets debug_info chunk from BEAM file
    chunks =
     case :beam_lib.chunks(bytecode, [:debug_info]) do
        {:ok, {_mod, chunks}} -> chunks
        {:error, _, error} -> throw("Error: #{inspect(error)}")
      end
    # Gets the (extended) Elixir abstract syntax tree from debug_info chunk
    dbgi_map =
      case chunks[:debug_info] do
        {:debug_info_v1, :elixir_erl, metadata} ->
          case metadata do
            {:elixir_v1, map, _} ->
              # Erlang extended AST available
              map
          end
        x ->
          throw("Error: #{inspect(x)}")
      end
    dbgi_map[:attributes]
    |> IO.inspect
  end
end

This outputs the following. &A.function1/0 is saved which is what was needed:

[description: "function1/0 returns :ok", description: &A.function1/0]

Compared to the Elixir module, you can set functions directly @callback foo. Can something cleaner (without the &a/0) be achieved?