Skip to content

Commit

Permalink
Fix incorrect source info in docstrings (#37048)
Browse files Browse the repository at this point in the history
Fixes #36906, where source info wasn't being passed through
at-doc when it was applied to definitions defined within macros.
  • Loading branch information
MichaelHatherly committed Aug 19, 2020
1 parent 0fd5833 commit 032cbc2
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
12 changes: 7 additions & 5 deletions base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -443,22 +443,22 @@ more than one expression is marked then the same docstring is applied to each ex
"""
:(Core.@__doc__)

function __doc__!(meta, def, define::Bool)
@nospecialize meta def
function __doc__!(source, mod, meta, def, define::Bool)
@nospecialize source mod meta def
# Two cases must be handled here to avoid redefining all definitions contained in `def`:
if define
# `def` has not been defined yet (this is the common case, i.e. when not generating
# the Base image). We just need to convert each `@__doc__` marker to an `@doc`.
finddoc(def) do each
each.head = :macrocall
each.args = [Symbol("@doc"), nothing, meta, each.args[end], define] # TODO: forward line number info
each.args = [Symbol("@doc"), source, mod, nothing, meta, each.args[end], define]
end
else
# `def` has already been defined during Base image gen so we just need to find and
# document any subexpressions marked with `@__doc__`.
docs = []
found = finddoc(def) do each
push!(docs, :(@doc($meta, $(each.args[end]), $define)))
push!(docs, :(@doc($source, $mod, $meta, $(each.args[end]), $define)))
end
# If any subexpressions have been documented then replace the entire expression with
# just those documented subexpressions to avoid redefining any definitions.
Expand Down Expand Up @@ -509,6 +509,8 @@ function docm(source::LineNumberNode, mod::Module, ex)
return REPL.lookup_doc(ex)
end
end
# Drop incorrect line numbers produced by nested macro calls.
docm(source::LineNumberNode, mod::Module, _, _, x...) = docm(source, mod, x...)

# iscallexpr checks if an expression is a :call expression. The call expression may be
# also part of a :where expression, so it unwraps the :where layers until it reaches the
Expand Down Expand Up @@ -578,7 +580,7 @@ function docm(source::LineNumberNode, mod::Module, meta, ex, define::Bool = true
# Errors generated by calling `macroexpand` are passed back to the call site.
isexpr(x, :error) ? esc(x) :
# When documenting macro-generated code we look for embedded `@__doc__` calls.
__doc__!(meta, x, define) ? esc(x) :
__doc__!(source, mod, meta, x, define) ? esc(x) :
# Any "basic" expression such as a bare function or module name or numeric literal.
isbasicdoc(x) ? objectdoc(source, mod, meta, nothing, x) :

Expand Down
17 changes: 17 additions & 0 deletions test/docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ macro example_1(f)
end |> esc
end

const LINE_NUMBER_F = @__LINE__() + 1
"f"
@example_1 f

Expand All @@ -446,16 +447,23 @@ macro example_2(f)
end |> esc
end

const LINE_NUMBER_G = @__LINE__() + 1
"g"
@example_2 g

@example_2 _g

const LINE_NUMBER_T = @__LINE__() + 1
"T"
Base.@kwdef struct T end

end

let md = meta(MacroGenerated)[@var(MacroGenerated.f)]
@test md.order == [Tuple{Any}]
@test docstrings_equal(md.docs[Tuple{Any}], doc"f")
@test md.docs[Tuple{Any}].data[:linenumber] == MacroGenerated.LINE_NUMBER_F
@test md.docs[Tuple{Any}].data[:path] == @__FILE__()
end

@test isdefined(MacroGenerated, :_f)
Expand All @@ -464,10 +472,19 @@ let md = meta(MacroGenerated)[@var(MacroGenerated.g)]
@test md.order == [Tuple{Any}, Tuple{Any, Any}]
@test docstrings_equal(md.docs[Tuple{Any}], doc"g")
@test docstrings_equal(md.docs[Tuple{Any, Any}], doc"g")
@test md.docs[Tuple{Any}].data[:linenumber] == MacroGenerated.LINE_NUMBER_G
@test md.docs[Tuple{Any}].data[:path] == @__FILE__()
end

@test isdefined(MacroGenerated, :_g)

let md = meta(MacroGenerated)[@var(MacroGenerated.T)]
@test md.order == Type[Union{}]
@test docstrings_equal(md.docs[Union{}], doc"T")
@test md.docs[Union{}].data[:linenumber] == MacroGenerated.LINE_NUMBER_T
@test md.docs[Union{}].data[:path] == @__FILE__()
end

module DocVars

struct __FIELDS__ end
Expand Down

0 comments on commit 032cbc2

Please sign in to comment.