• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.88
/base/path.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
export
4
    abspath,
5
    basename,
6
    dirname,
7
    expanduser,
8
    contractuser,
9
    homedir,
10
    isabspath,
11
    isdirpath,
12
    joinpath,
13
    normpath,
14
    realpath,
15
    relpath,
16
    splitdir,
17
    splitdrive,
18
    splitext,
19
    splitpath
20

21
if Sys.isunix()
22
    const path_separator    = "/"
23
    const path_separator_re = r"/+"sa
24
    const path_directory_re = r"(?:^|/)\.{0,2}$"sa
25
    const path_dir_splitter = r"^(.*?)(/+)([^/]*)$"sa
26
    const path_ext_splitter = r"^((?:.*/)?(?:\.|[^/\.])[^/]*?)(\.[^/\.]*|)$"sa
27

28
    splitdrive(path::String) = ("",path)
4✔
29
elseif Sys.iswindows()
30
    const path_separator    = "\\"
31
    const path_separator_re = r"[/\\]+"sa
32
    const path_absolute_re  = r"^(?:[A-Za-z]+:)?[/\\]"sa
33
    const path_directory_re = r"(?:^|[/\\])\.{0,2}$"sa
34
    const path_dir_splitter = r"^(.*?)([/\\]+)([^/\\]*)$"sa
35
    const path_ext_splitter = r"^((?:.*[/\\])?(?:\.|[^/\\\.])[^/\\]*?)(\.[^/\\\.]*|)$"sa
36

37
    function splitdrive(path::String)
×
38
        m = match(r"^([^\\]+:|\\\\[^\\]+\\[^\\]+|\\\\\?\\UNC\\[^\\]+\\[^\\]+|\\\\\?\\[^\\]+:|)(.*)$"sa, path)::AbstractMatch
×
39
        String(something(m.captures[1])), String(something(m.captures[2]))
×
40
    end
41
else
42
    error("path primitives for this OS need to be defined")
43
end
44

45

46
"""
47
    splitdrive(path::AbstractString) -> (AbstractString, AbstractString)
48

49
On Windows, split a path into the drive letter part and the path part. On Unix systems, the
50
first component is always the empty string.
51
"""
52
splitdrive(path::AbstractString)
53

54
"""
55
    homedir() -> String
56

57
Return the current user's home directory.
58

59
!!! note
60
    `homedir` determines the home directory via `libuv`'s `uv_os_homedir`. For details
61
    (for example on how to specify the home directory via environment variables), see the
62
    [`uv_os_homedir` documentation](http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir).
63
"""
64
function homedir()
2,793✔
65
    buf = Base.StringVector(AVG_PATH - 1) # space for null-terminator implied by StringVector
2,793✔
66
    sz = RefValue{Csize_t}(length(buf) + 1) # total buffer size including null
2,793✔
67
    while true
×
68
        rc = ccall(:uv_os_homedir, Cint, (Ptr{UInt8}, Ptr{Csize_t}), buf, sz)
2,802✔
69
        if rc == 0
2,802✔
70
            resize!(buf, sz[])
5,586✔
71
            return String(buf)
2,793✔
72
        elseif rc == Base.UV_ENOBUFS
9✔
73
            resize!(buf, sz[] - 1) # space for null-terminator implied by StringVector
9✔
74
        else
75
            uv_error("homedir()", rc)
×
76
        end
77
    end
9✔
78
end
79

80

81
if Sys.iswindows()
82
    isabspath(path::AbstractString) = occursin(path_absolute_re, path)
×
83
else
84
    isabspath(path::AbstractString) = startswith(path, '/')
2,657,281✔
85
end
86

87
"""
88
    isabspath(path::AbstractString) -> Bool
89

90
Determine whether a path is absolute (begins at the root directory).
91

92
# Examples
93
```jldoctest
94
julia> isabspath("/home")
95
true
96

97
julia> isabspath("home")
98
false
99
```
100
"""
101
isabspath(path::AbstractString)
102

103
"""
104
    isdirpath(path::AbstractString) -> Bool
105

106
Determine whether a path refers to a directory (for example, ends with a path separator).
107

108
# Examples
109
```jldoctest
110
julia> isdirpath("/home")
111
false
112

113
julia> isdirpath("/home/")
114
true
115
```
116
"""
117
isdirpath(path::String) = occursin(path_directory_re, splitdrive(path)[2])
701,249✔
118

119
"""
120
    splitdir(path::AbstractString) -> (AbstractString, AbstractString)
121

122
Split a path into a tuple of the directory name and file name.
123

124
# Examples
125
```jldoctest
126
julia> splitdir("/home/myuser")
127
("/home", "myuser")
128
```
129
"""
130
function splitdir(path::String)
11✔
131
    a, b = splitdrive(path)
×
132
    _splitdir_nodrive(a,b)
285,399✔
133
end
134

135
# Common splitdir functionality without splitdrive, needed for splitpath.
136
_splitdir_nodrive(path::String) = _splitdir_nodrive("", path)
108✔
137
function _splitdir_nodrive(a::String, b::String)
285,473✔
138
    m = match(path_dir_splitter,b)
285,473✔
139
    m === nothing && return (a,b)
285,473✔
140
    cs = m.captures
284,867✔
141
    getcapture(cs, i) = cs[i]::AbstractString
854,601✔
142
    c1, c2, c3 = getcapture(cs, 1), getcapture(cs, 2), getcapture(cs, 3)
284,867✔
143
    a = string(a, isempty(c1) ? c2[1] : c1)
569,519✔
144
    a, String(c3)
284,867✔
145
end
146

147
"""
148
    dirname(path::AbstractString) -> String
149

150
Get the directory part of a path. Trailing characters ('/' or '\\') in the path are
151
counted as part of the path.
152

153
# Examples
154
```jldoctest
155
julia> dirname("/home/myuser")
156
"/home"
157

158
julia> dirname("/home/myuser/")
159
"/home/myuser"
160
```
161

162
See also [`basename`](@ref).
163
"""
164
dirname(path::AbstractString) = splitdir(path)[1]
148,260✔
165

166
"""
167
    basename(path::AbstractString) -> String
168

169
Get the file name part of a path.
170

171
!!! note
172
    This function differs slightly from the Unix `basename` program, where trailing slashes are ignored,
173
    i.e. `\$ basename /foo/bar/` returns `bar`, whereas `basename` in Julia returns an empty string `""`.
174

175
# Examples
176
```jldoctest
177
julia> basename("/home/myuser/example.jl")
178
"example.jl"
179

180
julia> basename("/home/myuser/")
181
""
182
```
183

184
See also [`dirname`](@ref).
185
"""
186
basename(path::AbstractString) = splitdir(path)[2]
135,930✔
187

188
"""
189
    splitext(path::AbstractString) -> (String, String)
190

191
If the last component of a path contains one or more dots, split the path into everything before the
192
last dot and everything including and after the dot. Otherwise, return a tuple of the argument
193
unmodified and the empty string. "splitext" is short for "split extension".
194

195
# Examples
196
```jldoctest
197
julia> splitext("/home/myuser/example.jl")
198
("/home/myuser/example", ".jl")
199

200
julia> splitext("/home/myuser/example.tar.gz")
201
("/home/myuser/example.tar", ".gz")
202

203
julia> splitext("/home/my.user/example")
204
("/home/my.user/example", "")
205
```
206
"""
207
function splitext(path::String)
681✔
208
    a, b = splitdrive(path)
×
209
    m = match(path_ext_splitter, b)
681✔
210
    m === nothing && return (path,"")
681✔
211
    (a*something(m.captures[1])), String(something(m.captures[2]))
678✔
212
end
213

214
# NOTE: deprecated in 1.4
215
pathsep() = path_separator
×
216

217
"""
218
    splitpath(path::AbstractString) -> Vector{String}
219

220
Split a file path into all its path components. This is the opposite of
221
`joinpath`. Returns an array of substrings, one for each directory or file in
222
the path, including the root directory if present.
223

224
!!! compat "Julia 1.1"
225
    This function requires at least Julia 1.1.
226

227
# Examples
228
```jldoctest
229
julia> splitpath("/home/myuser/example.jl")
230
4-element Vector{String}:
231
 "/"
232
 "home"
233
 "myuser"
234
 "example.jl"
235
```
236
"""
237
splitpath(p::AbstractString) = splitpath(String(p))
22✔
238

239
function splitpath(p::String)
46✔
240
    drive, p = splitdrive(p)
×
241
    out = String[]
46✔
242
    isempty(p) && (pushfirst!(out,p))  # "" means the current directory.
46✔
243
    while !isempty(p)
140✔
244
        dir, base = _splitdir_nodrive(p)
108✔
245
        dir == p && (pushfirst!(out, dir); break)  # Reached root node.
122✔
246
        if !isempty(base)  # Skip trailing '/' in basename
94✔
247
            pushfirst!(out, base)
86✔
248
        end
249
        p = dir
×
250
    end
94✔
251
    if !isempty(drive)  # Tack the drive back on to the first element.
×
252
        out[1] = drive*out[1]  # Note that length(out) is always >= 1.
×
253
    end
254
    return out
46✔
255
end
256

257
if Sys.iswindows()
258

259
function joinpath(paths::Union{Tuple, AbstractVector})::String
×
260
    assertstring(x) = x isa AbstractString || throw(ArgumentError("path component is not a string: $(repr(x))"))
×
261

262
    isempty(paths) && throw(ArgumentError("collection of path components must be non-empty"))
×
263
    assertstring(paths[1])
×
264
    result_drive, result_path = splitdrive(paths[1])
×
265

266
    p_path = ""
×
267
    for i in firstindex(paths)+1:lastindex(paths)
×
268
        assertstring(paths[i])
×
269
        p_drive, p_path = splitdrive(paths[i])
×
270

271
        if startswith(p_path, ('\\', '/'))
×
272
            # second path is absolute
273
            if !isempty(p_drive) || !isempty(result_drive)
×
274
                result_drive = p_drive
×
275
            end
276
            result_path = p_path
×
277
            continue
×
278
        elseif !isempty(p_drive) && p_drive != result_drive
×
279
            if lowercase(p_drive) != lowercase(result_drive)
×
280
                # different drives, ignore the first path entirely
281
                result_drive = p_drive
×
282
                result_path = p_path
×
283
                continue
×
284
            end
285
        end
286

287
        # second path is relative to the first
288
        if !isempty(result_path) && result_path[end] ∉ ('\\', '/')
×
289
            result_path *= "\\"
×
290
        end
291

292
        result_path = result_path * p_path
×
293
    end
×
294

295
    # add separator between UNC and non-absolute path
296
    if !isempty(p_path) && result_path[1] ∉ ('\\', '/') && !isempty(result_drive) && result_drive[end] != ':'
×
297
        return result_drive * "\\" * result_path
×
298
    end
299

300
    return result_drive * result_path
×
301
end
302

303
else
304

305
function joinpath(paths::Union{Tuple, AbstractVector})::String
1,285,460✔
306
    assertstring(x) = x isa AbstractString || throw(ArgumentError("path component is not a string: $(repr(x))"))
304✔
307

308
    isempty(paths) && throw(ArgumentError("collection of path components must be non-empty"))
266✔
309
    assertstring(paths[1])
266✔
310
    path = paths[1]
1,285,460✔
311
    for i in firstindex(paths)+1:lastindex(paths)
1,285,472✔
312
        p = paths[i]
1,500,618✔
313
        assertstring(p)
695✔
314
        if isabspath(p)
1,510,622✔
315
            path = p
332✔
316
        elseif isempty(path) || path[end] == '/'
4,493,522✔
317
            path *= p
2,509✔
318
        else
319
            path *= "/" * p
1,497,777✔
320
        end
321
    end
1,715,801✔
322
    return path
1,285,460✔
323
end
324

325
end # os-test
326

327
joinpath(paths::AbstractString...)::String = joinpath(paths)
1,285,551✔
328

329
"""
330
    joinpath(parts::AbstractString...) -> String
331
    joinpath(parts::Vector{AbstractString}) -> String
332
    joinpath(parts::Tuple{AbstractString}) -> String
333

334
Join path components into a full path. If some argument is an absolute path or
335
(on Windows) has a drive specification that doesn't match the drive computed for
336
the join of the preceding paths, then prior components are dropped.
337

338
Note on Windows since there is a current directory for each drive, `joinpath("c:", "foo")`
339
represents a path relative to the current directory on drive "c:" so this is equal to "c:foo",
340
not "c:\\foo". Furthermore, `joinpath` treats this as a non-absolute path and ignores the drive
341
letter casing, hence `joinpath("C:\\A","c:b") = "C:\\A\\b"`.
342

343
# Examples
344
```jldoctest
345
julia> joinpath("/home/myuser", "example.jl")
346
"/home/myuser/example.jl"
347
```
348

349
```jldoctest
350
julia> joinpath(["/home/myuser", "example.jl"])
351
"/home/myuser/example.jl"
352
```
353
"""
354
joinpath
355

356
"""
357
    normpath(path::AbstractString) -> String
358

359
Normalize a path, removing "." and ".." entries and changing "/" to the canonical path separator
360
for the system.
361

362
# Examples
363
```jldoctest
364
julia> normpath("/home/myuser/../example.jl")
365
"/home/example.jl"
366

367
julia> normpath("Documents/Julia") == joinpath("Documents", "Julia")
368
true
369
```
370
"""
371
function normpath(path::String)
699,158✔
372
    isabs = isabspath(path)
699,164✔
373
    isdir = isdirpath(path)
699,158✔
374
    drive, path = splitdrive(path)
×
375
    parts = split(path, path_separator_re; keepempty=false)
699,158✔
376
    filter!(!=("."), parts)
699,158✔
377
    while true
705,797✔
378
        clean = true
×
379
        for j = 1:length(parts)-1
1,409,994✔
380
            if parts[j] != ".." && parts[j+1] == ".."
3,713,004✔
381
                deleteat!(parts, j:j+1)
13,278✔
382
                clean = false
×
383
                break
6,639✔
384
            end
385
        end
1,853,437✔
386
        clean && break
705,797✔
387
    end
6,639✔
388
    if isabs
699,158✔
389
        while !isempty(parts) && parts[1] == ".."
1,395,762✔
390
            popfirst!(parts)
×
391
        end
×
392
    elseif isempty(parts)
1,262✔
393
        push!(parts, ".")
14✔
394
    end
395
    path = join(parts, path_separator)
699,158✔
396
    if isabs
699,158✔
397
        path = path_separator*path
697,896✔
398
    end
399
    if isdir && !isdirpath(path)
699,158✔
400
        path *= path_separator
124✔
401
    end
402
    string(drive,path)
699,158✔
403
end
404

405
"""
406
    normpath(path::AbstractString, paths::AbstractString...) -> String
407

408
Convert a set of paths to a normalized path by joining them together and removing
409
"." and ".." entries. Equivalent to `normpath(joinpath(path, paths...))`.
410
"""
411
normpath(a::AbstractString, b::AbstractString...) = normpath(joinpath(a,b...))
9,768✔
412

413
"""
414
    abspath(path::AbstractString) -> String
415

416
Convert a path to an absolute path by adding the current directory if necessary.
417
Also normalizes the path as in [`normpath`](@ref).
418

419
# Example
420

421
If you are in a directory called `JuliaExample` and the data you are using is two levels up relative to the `JuliaExample` directory, you could write:
422

423
abspath("../../data")
424

425
Which gives a path like `"/home/JuliaUser/data/"`.
426

427
See also [`joinpath`](@ref), [`pwd`](@ref), [`expanduser`](@ref).
428
"""
429
function abspath(a::String)::String
711✔
430
    if !isabspath(a)
437,313✔
431
        cwd = pwd()
128✔
432
        a_drive, a_nodrive = splitdrive(a)
×
433
        if a_drive != "" && lowercase(splitdrive(cwd)[1]) != lowercase(a_drive)
×
434
            cwd = a_drive * path_separator
×
435
            a = joinpath(cwd, a_nodrive)
×
436
        else
437
            a = joinpath(cwd, a)
128✔
438
        end
439
    end
440
    return normpath(a)
437,313✔
441
end
442

443
"""
444
    abspath(path::AbstractString, paths::AbstractString...) -> String
445

446
Convert a set of paths to an absolute path by joining them together and adding the
447
current directory if necessary. Equivalent to `abspath(joinpath(path, paths...))`.
448
"""
449
abspath(a::AbstractString, b::AbstractString...) = abspath(joinpath(a,b...))
19,362✔
450

451
if Sys.iswindows()
452

453
function longpath(path::AbstractString)
×
454
    p = cwstring(path)
×
455
    buf = zeros(UInt16, length(p))
×
456
    while true
×
457
        n = ccall((:GetLongPathNameW, "kernel32"), stdcall,
×
458
            UInt32, (Ptr{UInt16}, Ptr{UInt16}, UInt32),
459
            p, buf, length(buf))
460
        windowserror(:longpath, n == 0)
×
461
        x = n < length(buf) # is the buffer big enough?
×
462
        resize!(buf, n) # shrink if x, grow if !x
×
463
        x && return transcode(String, buf)
×
464
    end
×
465
end
466

467
end # os-test
468

469

470
"""
471
    realpath(path::AbstractString) -> String
472

473
Canonicalize a path by expanding symbolic links and removing "." and ".." entries.
474
On case-insensitive case-preserving filesystems (typically Mac and Windows), the
475
filesystem's stored case for the path is returned.
476

477
(This function throws an exception if `path` does not exist in the filesystem.)
478
"""
479
function realpath(path::AbstractString)
122,426✔
480
    req = Libc.malloc(_sizeof_uv_fs)
122,426✔
481
    try
122,426✔
482
        ret = ccall(:uv_fs_realpath, Cint,
122,426✔
483
                    (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}),
484
                    C_NULL, req, path, C_NULL)
485
        if ret < 0
122,425✔
486
            uv_fs_req_cleanup(req)
1✔
487
            uv_error("realpath($(repr(path)))", ret)
1✔
488
        end
489
        path = unsafe_string(ccall(:jl_uv_fs_t_ptr, Cstring, (Ptr{Cvoid},), req))
122,424✔
490
        uv_fs_req_cleanup(req)
122,424✔
491
        return path
122,426✔
492
    finally
493
        Libc.free(req)
122,426✔
494
    end
495
end
496

497
if Sys.iswindows()
498
# on windows, ~ means "temporary file"
499
expanduser(path::AbstractString) = path
×
500
contractuser(path::AbstractString) = path
×
501
else
502
function expanduser(path::AbstractString)
2,042✔
503
    y = iterate(path)
4,055✔
504
    y === nothing && return path
2,042✔
505
    c, i = y::Tuple{eltype(path),Int}
23✔
506
    c != '~' && return path
2,016✔
507
    y = iterate(path, i)
8✔
508
    y === nothing && return homedir()
7✔
509
    y[1]::eltype(path) == '/' && return homedir() * path[i:end]
1✔
510
    throw(ArgumentError("~user tilde expansion not yet implemented"))
×
511
end
512
function contractuser(path::AbstractString)
2,410✔
513
    home = homedir()
2,410✔
514
    if path == home
2,410✔
515
        return "~"
2✔
516
    elseif startswith(path, home)
4,392✔
517
        return joinpath("~", relpath(path, home))
3✔
518
    else
519
        return path
2,405✔
520
    end
521
end
522
end
523

524

525
"""
526
    expanduser(path::AbstractString) -> AbstractString
527

528
On Unix systems, replace a tilde character at the start of a path with the current user's home directory.
529

530
See also: [`contractuser`](@ref).
531
"""
532
expanduser(path::AbstractString)
533

534
"""
535
    contractuser(path::AbstractString) -> AbstractString
536

537
On Unix systems, if the path starts with `homedir()`, replace it with a tilde character.
538

539
See also: [`expanduser`](@ref).
540
"""
541
contractuser(path::AbstractString)
542

543

544
"""
545
    relpath(path::AbstractString, startpath::AbstractString = ".") -> String
546

547
Return a relative filepath to `path` either from the current directory or from an optional
548
start directory. This is a path computation: the filesystem is not accessed to confirm the
549
existence or nature of `path` or `startpath`.
550

551
On Windows, case sensitivity is applied to every part of the path except drive letters. If
552
`path` and `startpath` refer to different drives, the absolute path of `path` is returned.
553
"""
554
function relpath(path::String, startpath::String = ".")
606✔
555
    isempty(path) && throw(ArgumentError("`path` must be non-empty"))
606✔
556
    isempty(startpath) && throw(ArgumentError("`startpath` must be non-empty"))
600✔
557
    curdir = "."
×
558
    pardir = ".."
×
559
    path == startpath && return curdir
598✔
560
    if Sys.iswindows()
×
561
        path_drive, path_without_drive = splitdrive(path)
×
562
        startpath_drive, startpath_without_drive = splitdrive(startpath)
×
563
        isempty(startpath_drive) && (startpath_drive = path_drive) # by default assume same as path drive
×
564
        uppercase(path_drive) == uppercase(startpath_drive) || return abspath(path) # if drives differ return first path
×
565
        path_arr  = split(abspath(path_drive * path_without_drive),      path_separator_re)
×
566
        start_arr = split(abspath(path_drive * startpath_without_drive), path_separator_re)
×
567
    else
568
        path_arr  = split(abspath(path),      path_separator_re)
586✔
569
        start_arr = split(abspath(startpath), path_separator_re)
586✔
570
    end
571
    i = 0
×
572
    while i < min(length(path_arr), length(start_arr))
3,188✔
573
        i += 1
2,835✔
574
        if path_arr[i] != start_arr[i]
3,048✔
575
            i -= 1
233✔
576
            break
233✔
577
        end
578
    end
2,602✔
579
    pathpart = join(path_arr[i+1:something(findlast(x -> !isempty(x), path_arr), 0)], path_separator)
1,232✔
580
    prefix_num = something(findlast(x -> !isempty(x), start_arr), 0) - i - 1
1,810✔
581
    if prefix_num >= 0
586✔
582
        prefix = pardir * path_separator
213✔
583
        relpath_ = isempty(pathpart)     ?
392✔
584
            (prefix^prefix_num) * pardir :
585
            (prefix^prefix_num) * pardir * path_separator * pathpart
586
    else
587
        relpath_ = pathpart
×
588
    end
589
    return isempty(relpath_) ? curdir :  relpath_
586✔
590
end
591
relpath(path::AbstractString, startpath::AbstractString) =
4✔
592
    relpath(String(path), String(startpath))
593

594
for f in (:isdirpath, :splitdir, :splitdrive, :splitext, :normpath, :abspath)
595
    @eval $f(path::AbstractString) = $f(String(path))
1,665✔
596
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc