Capture warnings with Code.with_diagnostics/2

almirsarajcic

almirsarajcic

51 minutes ago

0 comments

Use Code.with_diagnostics/2 when warnings and errors need to become structured data instead of terminal text.

source = ~S"""
defmodule Price do
  def total(items) do
    count = length(items)
    Enum.sum(items)
  end
end
"""

{_compiled, diagnostics} =
  Code.with_diagnostics(fn ->
    Code.compile_string(source, "price.ex")
  end)

Enum.map(diagnostics, fn diagnostic ->
  first_line = diagnostic.message |> String.split("\n") |> hd()
  {diagnostic.severity, diagnostic.position, first_line}
end)

# => [
#      {:warning, {3, 5},
#       "variable \"count\" is unused (if the variable is not meant to be used, prefix it with an underscore)"}
#    ]

Each diagnostic is a map containing fields such as :severity, :message, :file, :position, and :stacktrace, with optional span and detail data. That makes the result suitable for editor annotations, code-generation checks, or tests around dynamically compiled code.

Diagnostics are not printed by default while they are captured. Pass log: true when you want both structured results and the normal log output.

Code.with_diagnostics/2 does not rescue exceptions raised inside the function. Wrap the compilation in try/rescue if both the exception and the captured diagnostics must be returned as data. mix compile and Kernel.ParallelCompiler already capture diagnostics themselves.

Code.with_diagnostics/2 docs

Comments (0)

Sign in with GitHub to join the discussion