Skip to content

Commit

Permalink
Fix line numbering for Julia 1.5
Browse files Browse the repository at this point in the history
JuliaLang/julia#35138 changed it so that the
method's line number is the declaration, not the first line of the body.

This also reworks the line-number detection logic on older releases,
and it should be more robust.
  • Loading branch information
timholy committed Apr 16, 2020
1 parent 836d261 commit 8c5ff78
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 35 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ julia:
- 1.1
- 1.2
- 1.3
- 1.4
- nightly
notifications:
email: false
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Revise"
uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "2.6.0"
version = "2.6.1"

[deps]
CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
Expand All @@ -16,7 +16,7 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[compat]
CodeTracking = "~0.5.1"
CodeTracking = "0.5.9"
JuliaInterpreter = "~0.7.1"
LoweredCodeUtils = "0.4"
OrderedCollections = "1"
Expand Down
2 changes: 2 additions & 0 deletions src/Revise.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ using LoweredCodeUtils: next_or_nothing!, isanonymous_typedef, define_anonymous

export revise, includet, entr, MethodSummary

using CodeTracking: line_is_decl

"""
Revise.watching_files[]
Expand Down
91 changes: 61 additions & 30 deletions src/lowered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,47 +156,78 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, fra
pc, pc3 = ret
# Get the line number from the body
stmt3 = pc_expr(frame, pc3)
bodycode = stmt3.args[end]
if !isa(bodycode, CodeInfo)
bodycode = @lookup(frame, bodycode)
lnn = nothing
if line_is_decl
sigcode = @lookup(frame, stmt3.args[2])
lnn = sigcode[end]
if !isa(lnn, LineNumberNode)
lnn = nothing
end
end
if isa(bodycode, CodeInfo)
lnn = bodycode.linetable[1]
if lnn.line == 0 && lnn.file == :none && length(bodycode.code) > 1
# This may be a kwarg method. Mimic LoweredCodeUtils.bodymethod,
# except without having a method
stmt = bodycode.code[end-1]
if isa(stmt, Expr) && length(stmt.args) > 1
a = stmt.args[1]
hasself = any(i->LoweredCodeUtils.is_self_call(stmt, bodycode.slotnames, i), 2:length(stmt.args))
if hasself && isa(a, Symbol)
f = getfield(mod, stmt.args[1])
mths = methods(f)
if length(mths) == 1
mth = first(mths)
lnn = LineNumberNode(Int(mth.line), mth.file)
if lnn === nothing
bodycode = stmt3.args[end]
if !isa(bodycode, CodeInfo)
bodycode = @lookup(frame, bodycode)
end
if isa(bodycode, CodeInfo)
lnn = bodycode.linetable[1]
if lnn.line == 0 && lnn.file == :none
lnn = nothing
if length(bodycode.code) > 1
# This may be a kwarg method. Mimic LoweredCodeUtils.bodymethod,
# except without having a method
stmt = bodycode.code[end-1]
if isa(stmt, Expr) && length(stmt.args) > 1
a = stmt.args[1]
hasself = any(i->LoweredCodeUtils.is_self_call(stmt, bodycode.slotnames, i), 2:length(stmt.args))
if isa(a, Core.SlotNumber)
a = bodycode.slotnames[a.id]
end
if hasself && (isa(a, Symbol) || isa(a, GlobalRef))
thismod, thisname = isa(a, Symbol) ? (mod, a) : (a.mod, a.name)
if isdefined(thismod, thisname)
f = getfield(thismod, thisname)
mths = methods(f)
if length(mths) == 1
mth = first(mths)
lnn = LineNumberNode(Int(mth.line), mth.file)
end
end
end
end
end
else
# Just try to find *any* line number
for lnntmp in bodycode.linetable
if lnntmp.line != 0 || lnntmp.file != :none
lnn = lnntmp
break
if lnn === nothing
# Just try to find *any* line number
for lnntmp in bodycode.linetable
if lnntmp.line != 0 || lnntmp.file != :none
lnn = lnntmp
break
end
end
end
end
elseif isexpr(bodycode, :lambda)
lnntmp = bodycode.args[end][1]
if lnntmp.line != 0 || lnntmp.file != :none
lnn = lnntmp
end
end
for sig in signatures
add_signature!(methodinfo, sig, lnn)
end
if lnn === nothing
i = frame.framecode.src.codelocs[pc3]
while i > 0
lnntmp = frame.framecode.src.linetable[i]
if lnntmp.line != 0 || lnntmp.file != :none
lnn = lnntmp
break
end
i -= 1
end
elseif isexpr(bodycode, :lambda)
lnn = bodycode.args[end][1]
end
if lnn !== nothing && (lnn.line != 0 || lnn.file != :none)
for sig in signatures
add_signature!(methodinfo, sig, lnn)
end
else
error("unhandled bodycode ", bodycode)
end
end
elseif stmt.head == :(=) && isa(stmt.args[1], Symbol)
Expand Down
12 changes: 9 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ using OrderedCollections: OrderedSet
using Test: collect_test_logs
using Base.CoreLogging: Debug,Info

using CodeTracking: line_is_decl

include("common.jl")

throwing_function(bt) = bt[2]
Expand Down Expand Up @@ -1263,13 +1265,16 @@ foo(y::Int) = y-51
triggered(true, false)
@test false
catch err
bt = throwing_function(Revise.update_stacktrace_lineno!(stacktrace(catch_backtrace())))
st = stacktrace(catch_backtrace())
Revise.update_stacktrace_lineno!(st)
bt = throwing_function(st)
@test bt.file == Symbol(filename) && bt.line == 2
end
io = IOBuffer()
if isdefined(Base, :methodloc_callback)
print(io, methods(triggered))
@test occursin(filename * ":2", String(take!(io)))
mline = line_is_decl ? 1 : 2
@test occursin(filename * ":$mline", String(take!(io)))
end
open(filename, "w") do io
println(io, """
Expand Down Expand Up @@ -1306,7 +1311,8 @@ foo(y::Int) = y-51
@test occursin(targetstr, String(take!(io)))
if isdefined(Base, :methodloc_callback)
print(io, methods(triggered))
@test occursin(filename * ":3", String(take!(io)))
mline = line_is_decl ? 2 : 3
@test occursin(filename * ":$mline", String(take!(io)))
end

push!(to_remove, filename)
Expand Down

0 comments on commit 8c5ff78

Please sign in to comment.