Skip to content

Commit 524bb5e

Browse files
committed
Don't eagerly absolutize source file paths.
1 parent 03971b4 commit 524bb5e

File tree

6 files changed

+146
-114
lines changed

6 files changed

+146
-114
lines changed

bindgen/clang.rs

Lines changed: 99 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
use crate::ir::context::{BindgenContext, IncludeLocation};
88
use clang_sys::*;
9+
use std::borrow::Cow;
910
use std::cmp;
1011
use std::convert::TryInto;
12+
use std::env::current_dir;
1113
use std::ffi::{CStr, CString};
1214
use std::fmt;
1315
use std::hash::Hash;
@@ -396,9 +398,8 @@ impl Cursor {
396398
offset: offset.try_into().unwrap(),
397399
}
398400
} else {
399-
let file_name = cxstring_into_string(clang_getFileName(file));
400401
SourceLocation::File {
401-
file_path: absolutize_path(file_name),
402+
file: SourceFile::from_raw(file),
402403
line: line.try_into().unwrap(),
403404
column: column.try_into().unwrap(),
404405
offset: offset.try_into().unwrap(),
@@ -536,12 +537,8 @@ impl Cursor {
536537
let mut children = self.collect_children();
537538
for child in &children {
538539
if child.kind() == CXCursor_InclusionDirective {
539-
if let Some(included_file_name) = child.get_included_file_name()
540-
{
541-
ctx.add_include(
542-
absolutize_path(included_file_name),
543-
child.location(),
544-
);
540+
if let Some(included_file) = child.get_included_file() {
541+
ctx.add_include(included_file, child.location());
545542
}
546543
}
547544
}
@@ -934,14 +931,12 @@ impl Cursor {
934931
/// Obtain the real path name of a cursor of InclusionDirective kind.
935932
///
936933
/// Returns None if the cursor does not include a file, otherwise the file's full name
937-
pub(crate) fn get_included_file_name(&self) -> Option<String> {
938-
let file = unsafe { clang_sys::clang_getIncludedFile(self.x) };
934+
pub(crate) fn get_included_file(&self) -> Option<SourceFile> {
935+
let file = unsafe { clang_getIncludedFile(self.x) };
939936
if file.is_null() {
940937
None
941938
} else {
942-
Some(unsafe {
943-
cxstring_into_string(clang_sys::clang_getFileName(file))
944-
})
939+
Some(unsafe { SourceFile::from_raw(file) })
945940
}
946941
}
947942
}
@@ -1579,8 +1574,8 @@ pub(crate) enum SourceLocation {
15791574
},
15801575
/// Location in a source file.
15811576
File {
1582-
/// Name of the source file.
1583-
file_path: PathBuf,
1577+
/// The source file.
1578+
file: SourceFile,
15841579
/// Line in the source file.
15851580
line: usize,
15861581
/// Column in the source file.
@@ -1590,18 +1585,6 @@ pub(crate) enum SourceLocation {
15901585
},
15911586
}
15921587

1593-
fn absolutize_path<P: AsRef<Path>>(path: P) -> PathBuf {
1594-
let path = path.as_ref();
1595-
1596-
if path.is_relative() {
1597-
std::env::current_dir()
1598-
.expect("Cannot retrieve current directory")
1599-
.join(path)
1600-
} else {
1601-
path.to_owned()
1602-
}
1603-
}
1604-
16051588
impl SourceLocation {
16061589
/// Locations of built-in items provided by the compiler (which don't have a source file),
16071590
/// are sorted first. Remaining locations are sorted by their position in the source file.
@@ -1625,59 +1608,64 @@ impl SourceLocation {
16251608
other.cmp_by_source_order(self, ctx).reverse()
16261609
}
16271610
(
1611+
SourceLocation::File { file, offset, .. },
16281612
SourceLocation::File {
1629-
file_path, offset, ..
1630-
},
1631-
SourceLocation::File {
1632-
file_path: other_file_path,
1613+
file: other_file,
16331614
offset: other_offset,
16341615
..
16351616
},
16361617
) => {
1618+
let file_path = file.path();
1619+
let other_file_path = other_file.path();
1620+
16371621
if file_path == other_file_path {
16381622
return offset.cmp(other_offset);
16391623
}
16401624

16411625
// If `file` is transitively included via `ancestor_file`,
16421626
// find the offset of the include directive in `ancestor_file`.
1643-
let offset_in_ancestor = |file: &Path, ancestor_file: &Path| {
1644-
let mut file = file;
1645-
while file != ancestor_file {
1646-
let include_location = ctx.include_location(file);
1647-
file = if let IncludeLocation::File {
1648-
file_path: file,
1649-
offset,
1650-
..
1651-
} = include_location
1652-
{
1653-
if file == ancestor_file {
1654-
return Some(offset);
1627+
let offset_in_ancestor =
1628+
|file_path: &Path, ancestor_file_path: &Path| {
1629+
let mut file_path = Cow::Borrowed(file_path);
1630+
while file_path != ancestor_file_path {
1631+
let include_location =
1632+
ctx.include_location(file_path);
1633+
file_path = if let IncludeLocation::File {
1634+
file,
1635+
offset,
1636+
..
1637+
} = include_location
1638+
{
1639+
let file_path = Cow::Owned(file.path());
1640+
1641+
if file_path == ancestor_file_path {
1642+
return Some(offset);
1643+
}
1644+
1645+
file_path
1646+
} else {
1647+
break;
16551648
}
1656-
1657-
file
1658-
} else {
1659-
break;
16601649
}
1661-
}
16621650

1663-
None
1664-
};
1651+
None
1652+
};
16651653

16661654
if let Some(offset) =
1667-
offset_in_ancestor(file_path, other_file_path)
1655+
offset_in_ancestor(&file_path, &other_file_path)
16681656
{
16691657
return offset.cmp(other_offset);
16701658
}
16711659

16721660
if let Some(other_offset) =
1673-
offset_in_ancestor(other_file_path, file_path)
1661+
offset_in_ancestor(&other_file_path, &file_path)
16741662
{
16751663
return offset.cmp(other_offset);
16761664
}
16771665

16781666
// If the source files are siblings, compare their include locations.
16791667
let parent = ctx.include_location(file_path);
1680-
let other_parent = ctx.include_location(other_file_path);
1668+
let other_parent = ctx.include_location(&other_file_path);
16811669
parent.cmp_by_source_order(other_parent, ctx)
16821670
}
16831671
}
@@ -1689,11 +1677,8 @@ impl fmt::Display for SourceLocation {
16891677
match self {
16901678
Self::Builtin { .. } => "built-in".fmt(f),
16911679
Self::File {
1692-
file_path,
1693-
line,
1694-
column,
1695-
..
1696-
} => write!(f, "{}:{}:{}", file_path.display(), line, column),
1680+
file, line, column, ..
1681+
} => write!(f, "{}:{}:{}", file.path().display(), line, column),
16971682
}
16981683
}
16991684
}
@@ -1803,17 +1788,63 @@ impl Iterator for CommentAttributesIterator {
18031788
}
18041789
}
18051790

1806-
fn cxstring_to_string_leaky(s: CXString) -> String {
1791+
/// A source file.
1792+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1793+
pub(crate) struct SourceFile {
1794+
name: Box<str>,
1795+
}
1796+
1797+
impl SourceFile {
1798+
/// Creates a new `SourceFile` from a file name.
1799+
#[inline]
1800+
pub fn new<P: AsRef<str>>(name: P) -> Self {
1801+
Self {
1802+
name: name.as_ref().to_owned().into_boxed_str(),
1803+
}
1804+
}
1805+
1806+
/// Creates a new `SourceFile` from a raw pointer.
1807+
///
1808+
/// # Safety
1809+
///
1810+
/// `file` must point to a valid `CXFile`.
1811+
pub unsafe fn from_raw(file: CXFile) -> Self {
1812+
let name = unsafe { cxstring_into_string(clang_getFileName(file)) };
1813+
1814+
Self::new(name)
1815+
}
1816+
1817+
#[inline]
1818+
pub fn name(&self) -> &str {
1819+
&self.name
1820+
}
1821+
1822+
/// Get the path of this source file.
1823+
pub fn path(&self) -> PathBuf {
1824+
let path = Path::new(self.name());
1825+
if path.is_relative() {
1826+
current_dir()
1827+
.expect("Cannot retrieve current directory")
1828+
.join(path)
1829+
} else {
1830+
path.to_owned()
1831+
}
1832+
}
1833+
}
1834+
1835+
unsafe fn cxstring_to_string_leaky(s: CXString) -> String {
18071836
if s.data.is_null() {
1808-
return "".to_owned();
1837+
Cow::Borrowed("")
1838+
} else {
1839+
let c_str = CStr::from_ptr(clang_getCString(s) as *const _);
1840+
c_str.to_string_lossy()
18091841
}
1810-
let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) };
1811-
c_str.to_string_lossy().into_owned()
1842+
.into_owned()
18121843
}
18131844

1814-
fn cxstring_into_string(s: CXString) -> String {
1845+
unsafe fn cxstring_into_string(s: CXString) -> String {
18151846
let ret = cxstring_to_string_leaky(s);
1816-
unsafe { clang_disposeString(s) };
1847+
clang_disposeString(s);
18171848
ret
18181849
}
18191850

@@ -1924,13 +1955,13 @@ impl TranslationUnit {
19241955
}
19251956
}
19261957

1927-
/// Get the source file path of this translation unit.
1928-
pub(crate) fn path(&self) -> PathBuf {
1929-
let file_name = unsafe {
1958+
/// Get the source file of this.
1959+
pub fn file(&self) -> SourceFile {
1960+
let name = unsafe {
19301961
cxstring_into_string(clang_getTranslationUnitSpelling(self.x))
19311962
};
19321963

1933-
absolutize_path(file_name)
1964+
SourceFile::new(name)
19341965
}
19351966

19361967
/// Is this the null translation unit?

bindgen/codegen/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4379,12 +4379,13 @@ fn unsupported_abi_diagnostic(
43794379
);
43804380

43814381
if let Some(crate::clang::SourceLocation::File {
4382-
file_path,
4382+
file,
43834383
line,
43844384
column,
43854385
..
43864386
}) = location.cloned()
43874387
{
4388+
let file_path = file.path();
43884389
if let Ok(Some(source)) = get_line(&file_path, line) {
43894390
let mut slice = Slice::default();
43904391
slice
@@ -4420,12 +4421,13 @@ fn variadic_fn_diagnostic(
44204421
.add_annotation("No code will be generated for this function.", Level::Note);
44214422

44224423
if let Some(crate::clang::SourceLocation::File {
4423-
file_path,
4424+
file,
44244425
line,
44254426
column,
44264427
..
44274428
}) = location.cloned()
44284429
{
4430+
let file_path = file.path();
44294431
if let Ok(Some(source)) = get_line(&file_path, line) {
44304432
let mut slice = Slice::default();
44314433
slice

bindgen/deps.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
/// Generating build depfiles from parsed bindings.
22
use std::{collections::BTreeSet, path::PathBuf};
33

4+
use crate::clang::SourceFile;
5+
46
#[derive(Clone, Debug)]
57
pub(crate) struct DepfileSpec {
68
pub output_module: String,
79
pub depfile_path: PathBuf,
810
}
911

1012
impl DepfileSpec {
11-
pub fn write(&self, deps: &BTreeSet<Box<str>>) -> std::io::Result<()> {
13+
pub fn write(&self, deps: &BTreeSet<SourceFile>) -> std::io::Result<()> {
1214
std::fs::write(&self.depfile_path, self.to_string(deps))
1315
}
1416

15-
fn to_string(&self, deps: &BTreeSet<Box<str>>) -> String {
17+
fn to_string(&self, deps: &BTreeSet<SourceFile>) -> String {
1618
// Transforms a string by escaping spaces and backslashes.
1719
let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ ");
1820

1921
let mut buf = format!("{}:", escape(&self.output_module));
2022
for file in deps {
21-
buf = format!("{} {}", buf, escape(file));
23+
buf = format!("{} {}", buf, escape(file.name()));
2224
}
2325
buf
2426
}
@@ -36,13 +38,13 @@ mod tests {
3638
};
3739

3840
let deps: BTreeSet<_> = vec![
39-
r"/absolute/path".into(),
40-
r"C:\win\absolute\path".into(),
41-
r"../relative/path".into(),
42-
r"..\win\relative\path".into(),
43-
r"../path/with spaces/in/it".into(),
44-
r"..\win\path\with spaces\in\it".into(),
45-
r"path\with/mixed\separators".into(),
41+
SourceFile::new(r"/absolute/path"),
42+
SourceFile::new(r"C:\win\absolute\path"),
43+
SourceFile::new(r"../relative/path"),
44+
SourceFile::new(r"..\win\relative\path"),
45+
SourceFile::new(r"../path/with spaces/in/it"),
46+
SourceFile::new(r"..\win\path\with spaces\in\it"),
47+
SourceFile::new(r"path\with/mixed\separators"),
4648
]
4749
.into_iter()
4850
.collect();

0 commit comments

Comments
 (0)