From b6f20aeac0b81c23d64deef827a67b38631b593a Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 2 Mar 2019 06:10:58 -0600 Subject: [PATCH] Add some convenience methods for line number correction --- README.md | 11 +++++++++-- src/CodeTracking.jl | 26 ++++++++++++++++++++++++++ test/runtests.jl | 12 +++++++++++- test/script.jl | 8 ++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 45e1cf1..665b7e1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ CodeTracking is a minimal package designed to work with (a future version of) [Revise.jl](https://github.com/timholy/Revise.jl). Its main purpose is to support packages that need to interact with code that might move -around as it's edited. +around as it gets edited. CodeTracking is a very lightweight dependency. @@ -23,7 +23,10 @@ In this (ficticious) example, `sum` moved because I deleted a few lines higher i these didn't affect the functionality of `sum` (so we didn't need to redefine and recompile it), but it does change the starting line number of the file at which this method appears. -Other features: +Other methods of `whereis` allow you to obtain the current position corresponding to a single +statement inside a method; see `?whereis` for details. + +CodeTracking can also be used to find out what files define a particular package: ```julia julia> using CodeTracking, ColorTypes @@ -32,7 +35,11 @@ julia> pkgfiles(ColorTypes) PkgFiles(ColorTypes [3da002f7-5984-5a60-b8a6-cbb66c0b333f]): basedir: /home/tim/.julia/packages/ColorTypes/BsAWO files: ["src/ColorTypes.jl", "src/types.jl", "src/traits.jl", "src/conversions.jl", "src/show.jl", "src/operations.jl"] +``` +or to extract the expression that defines a method: + +```julia julia> m = @which red(RGB(1,1,1)) red(c::AbstractRGB) in ColorTypes at /home/tim/.julia/packages/ColorTypes/BsAWO/src/traits.jl:14 diff --git a/src/CodeTracking.jl b/src/CodeTracking.jl index 0978705..6e94a4c 100644 --- a/src/CodeTracking.jl +++ b/src/CodeTracking.jl @@ -41,6 +41,32 @@ function whereis(method::Method) return normpath(file), line end +""" + loc = whereis(sf::StackFrame) + +Return location information for a single frame of a stack trace. +If `sf` corresponds to a frame that was inlined, `loc` will be `nothing`. +Otherwise `loc` will be `(filepath, line)`. +""" +function whereis(sf::StackTraces.StackFrame) + sf.linfo === nothing && return nothing + return whereis(sf, sf.linfo.def) +end + +""" + filepath, line = whereis(lineinfo, method::Method) + +Return the file and line number associated with a specific statement in `method`. +`lineinfo.line` should contain the line number of the statement at the time `method` +was compiled. The current location is returned. +""" +function whereis(lineinfo, method::Method) + file, line1 = whereis(method) + return file, lineinfo.line-method.line+line1 +end + + + """ src = definition(method::Method, String) diff --git a/test/runtests.jl b/test/runtests.jl index 68bc11f..10a3b43 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,7 +7,17 @@ include("script.jl") @testset "CodeTracking.jl" begin m = first(methods(f1)) file, line = whereis(m) - @test file == normpath(joinpath(@__DIR__, "script.jl")) + scriptpath = normpath(joinpath(@__DIR__, "script.jl")) + @test file == scriptpath + @test line == 3 + trace = try + call_throws() + catch + stacktrace(catch_backtrace()) + end + @test whereis(trace[2]) == (scriptpath, 10) + @test whereis(trace[3]) === nothing + src = definition(m, String) @test src == """ function f1(x, y) diff --git a/test/script.jl b/test/script.jl index 49f08f4..b3a0eb7 100644 --- a/test/script.jl +++ b/test/script.jl @@ -1,5 +1,13 @@ +# NOTE: tests are sensitive to the line number at which statements appear function f1(x, y) return x + y end f2(x, y) = x + y + +@noinline function throws() + x = nothing + error("oops") +end +@inline inlined() = throws() +call_throws() = inlined()