Locating a method defined through a macro

I’ve often encountered a problem figuring out where a method is defined when it’s definition happens through a macro. For example:

macro foo()
    :(bar() = x)
end

@foo()

bar()

This gives an UndefVarError with a stacktrace pointing to line 2 (inside the foo macro), but not showing line 5, where the definition was expanded from (usually, of course, it won’t be in the same file).
How can I find this information? Is it even stored anywhere? It doesn’t seem to be anywhere in the Method object (@which bar()).

you can make it work to do that, but it is not easy.
And the user can’t do it, it needs to be written into the macro, to tell it that the location of code defined inside it is the location the macro was called from.

Here is how it is done in ChainRulesCore’s @thunk macro
https://github.com/JuliaDiff/ChainRulesCore.jl/blob/a1a8da5e5d8a3772d725a0a0292dd84b36c2e9b6/src/differentials/thunks.jl#L21-L26
the important bit is the insertion of __source__ into the output.

2 Likes

I just found an old-ish issue about this problem, which contains one useful hint: a Method’s module field is the macro’s caller, so at least that’s some starting point in looking for it.

https://github.com/JuliaLang/julia/issues/31197

I’ve now created a package (https://github.com/yha/FindDefinition.jl) for solving this problem, using hints from the above issue:

julia> using StatsPlots

julia> using FindDefinition

julia> methods(StatsPlots.qqplot)
# 1 method for generic function "qqplot":
[1] qqplot(args...; kw...) in StatsPlots at [...]\.julia\packages\RecipesBase\92zOw\src\RecipesBase.jl:357

julia> finddefs(StatsPlots.qqplot)
1-element Array{LineNumberNode,1}:
 :(#= [...]\.julia\packages\StatsPlots\IMY3F\src\distributions.jl:96 =#)
1 Like