From bf687e75e7662167345d2a847780d7f55b1f7e40 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 9 Nov 2023 14:11:54 +0100 Subject: [PATCH] Filter out more doc signature expressions Revise extracts the documented expression and puts that before the full doc expression in the revision queue. E.g. in `"docs" f(x) = x` there will be a revision of `f(x) = x` followed by a revision of the full expresion (`"docs" f(x) = x`). However, in many cases a docstring is only attached to a signature (not a function body/struct definition, etc.) and in this case the revision of the signature is not needed. Revise already filters out the base case, `"docs" f(x)`. This patch extends this filtering to also apply to `where`-clauses such as e.g. `"docs" f(x::T) where T <: Integer`. Concretely, this patch fixes #735, i.e. revising doc expressions where the signature doesn't lower without the context of the doc macro. As a bonus, slightly less work has to be done for e.g. `"docs" f(x::T) where T` since this is also filtered out. --- src/utils.jl | 11 ++++++++++- test/runtests.jl | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/utils.jl b/src/utils.jl index 626474eb..c0b65577 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -90,11 +90,20 @@ istrivial(a) = a === nothing || isa(a, LineNumberNode) isgoto(stmt) = isa(stmt, Core.GotoNode) | isexpr(stmt, :gotoifnot) +function unwrap_where(ex::Expr) + while isexpr(ex, :where) + ex = ex.args[1] + end + return ex +end + function pushex!(exsigs::ExprsSigs, ex::Expr) uex = unwrap(ex) if is_doc_expr(uex) body = uex.args[4] - if isa(body, Expr) && body.head !== :call # don't trigger for docexprs like `"docstr" f(x::Int)` + # Don't trigger for exprs where the documented expression is just a signature + # (e.g. `"docstr" f(x::Int)`, `"docstr" f(x::T) where T` etc.) + if isa(body, Expr) && unwrap_where(body).head !== :call exsigs[RelocatableExpr(body)] = nothing end if length(uex.args) < 5 diff --git a/test/runtests.jl b/test/runtests.jl index 23f33d06..27627fcd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1112,6 +1112,23 @@ const issue639report = [] pop!(LOAD_PATH) end + do_test("doc expr signature") && @testset "Docstring attached to signatures" begin + md = Revise.ModuleExprsSigs(Main) + Revise.parse_source!(md, """ + module DocstringSigsOnly + function f end + "basecase" f(x) + "basecase with type" f(x::Int) + "basecase no varname" f(::Float64) + "where" f(x::T) where T <: Int8 + "where no varname" f(::T) where T <: String + end + """, "test2", Main) + # Simply test that the "bodies" of the doc exprs are not included as + # standalone expressions. + @test length(md[Main.DocstringSigsOnly]) == 6 # 1 func + 5 doc exprs + end + do_test("Undef in docstrings") && @testset "Undef in docstrings" begin fn = Base.find_source_file("abstractset.jl") # has lots of examples of """str""" func1, func2 mexsold = Revise.parse_source(fn, Base)