From 96a3c74f6ea1e8d3ee96ff0e6127bc9154941eb5 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 28 Jul 2021 04:34:45 -0500 Subject: [PATCH] Get tests working on recent Julia versions This also exposed some previously-untested functionality on Julia 1.0, in particular the absence of `splitpath` on Julia 1.0. I'm not sure what could have changed, but maybe the improvement to `checkname` ended up hitting new code paths on 1.0? --- src/CodeTracking.jl | 2 +- src/utils.jl | 35 +++++++++++++++++++++++++++++++++++ test/runtests.jl | 6 ++++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/CodeTracking.jl b/src/CodeTracking.jl index 70b9538..c561667 100644 --- a/src/CodeTracking.jl +++ b/src/CodeTracking.jl @@ -143,7 +143,7 @@ function signatures_at(filename::AbstractString, line::Integer) spath = splitpath(rpath) libname = spath[1] project = Base.active_project() - id = PkgId(Base.project_deps_get(project, libname), libname) + id = getpkgid(project, libname) return signatures_at(id, joinpath(spath[2:end]...), line) end if startswith(filename, "REPL[") diff --git a/src/utils.jl b/src/utils.jl index cf2f973..8a8a367 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,7 +1,10 @@ function checkname(fdef::Expr, name) fproto = fdef.args[1] fdef.head === :where && return checkname(fproto, name) + fdef.head === :call || return false if fproto isa Expr + # A metaprogramming-generated function + fproto.head === :$ && return true # uncheckable, let's assume all is well # Is the check below redundant? fproto.head === :. || return false # E.g. `function Mod.bar.foo(a, b)` @@ -137,3 +140,35 @@ function postpath(filename, pre) post[1:1] == Base.Filesystem.path_separator && return post[2:end] return post end + +if Base.VERSION < v"1.1" + function splitpath(p::String) + # splitpath became available with Julia 1.1 + # Implementation copied from Base except doesn't handle the drive + out = String[] + isempty(p) && (pushfirst!(out,p)) # "" means the current directory. + while !isempty(p) + dir, base = _splitdir_nodrive(p) + dir == p && (pushfirst!(out, dir); break) # Reached root node. + if !isempty(base) # Skip trailing '/' in basename + pushfirst!(out, base) + end + p = dir + end + return out + end + splitpath(p::AbstractString) = splitpath(String(p)) + + _splitdir_nodrive(path::String) = _splitdir_nodrive("", path) + function _splitdir_nodrive(a::String, b::String) + m = match(Base.Filesystem.path_dir_splitter,b) + m === nothing && return (a,b) + a = string(a, isempty(m.captures[1]) ? m.captures[2][1] : m.captures[1]) + a, String(m.captures[3]) + end +end + +# Robust across Julia versions +getpkgid(project::AbstractString, libname) = getpkgid(Base.project_deps_get(project, libname), libname) +getpkgid(id::PkgId, libname) = id +getpkgid(uuid::UUID, libname) = PkgId(uuid, libname) diff --git a/test/runtests.jl b/test/runtests.jl index 7ab5447..9909b71 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -131,7 +131,7 @@ isdefined(Main, :Revise) ? Main.Revise.includet("script.jl") : include("script.j # Ensure that we don't error on difficult cases m = which(+, (AbstractSparseVector, AbstractSparseVector)) # defined inside an `@eval` d = definition(String, m) - @test d === nothing || isa(d[1], String) + @test d === nothing || isa(d[1], AbstractString) # Check for existence of file id = Base.PkgId("__PackagePrecompilationStatementModule") # not all Julia versions have this @@ -149,7 +149,9 @@ end @test !isempty(sigs) ex = @code_expr(gcd(10, 20)) @test ex isa Expr - @test occursin(String(m.file), String(ex.args[2].args[2].args[1].file)) + body = ex.args[2] + idx = findfirst(x -> isa(x, LineNumberNode), body.args) + @test occursin(String(m.file), String(body.args[idx].file)) @test ex == code_expr(gcd, Tuple{Int,Int}) m = first(methods(edit))