Skip to content

Commit ba78db3

Browse files
libsyntax: factor out file path resolving
This allows the same logic used by `include_X!` macros to be used by `#[doc(include)]`.
1 parent 3ebca72 commit ba78db3

File tree

3 files changed

+35
-27
lines changed

3 files changed

+35
-27
lines changed

src/libsyntax/ext/source_util.rs

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ use crate::print::pprust;
66
use crate::ptr::P;
77
use crate::symbol::Symbol;
88
use crate::tokenstream;
9+
use crate::util::path;
910

1011
use smallvec::SmallVec;
11-
use syntax_pos::{self, Pos, Span, FileName};
12+
use syntax_pos::{self, Pos, Span};
1213

1314
use std::fs;
1415
use std::io::ErrorKind;
15-
use std::path::PathBuf;
1616
use rustc_data_structures::sync::Lrc;
1717

1818
// These macros all relate to the file system; they either return
@@ -78,9 +78,9 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea
7878
None => return DummyResult::any(sp),
7979
};
8080
// The file will be added to the code map by the parser
81-
let path = res_rel_file(cx, sp, file);
81+
let file = path::resolve(file, sp, cx.source_map());
8282
let directory_ownership = DirectoryOwnership::Owned { relative: None };
83-
let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp);
83+
let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
8484

8585
struct ExpandResult<'a> {
8686
p: parse::parser::Parser<'a>,
@@ -115,7 +115,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::To
115115
Some(f) => f,
116116
None => return DummyResult::expr(sp)
117117
};
118-
let file = res_rel_file(cx, sp, file);
118+
let file = path::resolve(file, sp, cx.source_map());
119119
match fs::read_to_string(&file) {
120120
Ok(src) => {
121121
let interned_src = Symbol::intern(&src);
@@ -143,7 +143,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
143143
Some(f) => f,
144144
None => return DummyResult::expr(sp)
145145
};
146-
let file = res_rel_file(cx, sp, file);
146+
let file = path::resolve(file, sp, cx.source_map());
147147
match fs::read(&file) {
148148
Ok(bytes) => {
149149
// Add the contents to the source map if it contains UTF-8.
@@ -164,24 +164,3 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::
164164
}
165165
}
166166
}
167-
168-
// resolve a file-system path to an absolute file-system path (if it
169-
// isn't already)
170-
fn res_rel_file(cx: &mut ExtCtxt<'_>, sp: syntax_pos::Span, arg: String) -> PathBuf {
171-
let arg = PathBuf::from(arg);
172-
// Relative paths are resolved relative to the file in which they are found
173-
// after macro expansion (that is, they are unhygienic).
174-
if !arg.is_absolute() {
175-
let callsite = sp.source_callsite();
176-
let mut path = match cx.source_map().span_to_unmapped_path(callsite) {
177-
FileName::Real(path) => path,
178-
FileName::DocTest(path, _) => path,
179-
other => panic!("cannot resolve relative path in non-file source `{}`", other),
180-
};
181-
path.pop();
182-
path.push(arg);
183-
path
184-
} else {
185-
arg
186-
}
187-
}

src/libsyntax/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub mod util {
135135
#[cfg(test)]
136136
pub mod parser_testing;
137137
pub mod map_in_place;
138+
pub mod path;
138139
}
139140

140141
pub mod json;

src/libsyntax/util/path.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use crate::source_map::SourceMap;
2+
use std::path::PathBuf;
3+
use syntax_pos::{Span, FileName};
4+
5+
/// Resolve a path mentioned inside Rust code.
6+
///
7+
/// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
8+
///
9+
/// Returns an absolute path to the file that `path` refers to.
10+
pub fn resolve(path: impl Into<PathBuf>, span: Span, map: &SourceMap) -> PathBuf {
11+
let path = path.into();
12+
13+
// Relative paths are resolved relative to the file in which they are found
14+
// after macro expansion (that is, they are unhygienic).
15+
if !path.is_absolute() {
16+
let callsite = span.source_callsite();
17+
let mut result = match map.span_to_unmapped_path(callsite) {
18+
FileName::Real(path) => path,
19+
FileName::DocTest(path, _) => path,
20+
other => panic!("cannot resolve relative path in non-file source `{}`", other),
21+
};
22+
result.pop();
23+
result.push(path);
24+
result
25+
} else {
26+
path
27+
}
28+
}

0 commit comments

Comments
 (0)