6
6
7
7
use crate :: ir:: context:: { BindgenContext , IncludeLocation } ;
8
8
use clang_sys:: * ;
9
+ use std:: borrow:: Cow ;
9
10
use std:: cmp;
10
11
use std:: convert:: TryInto ;
12
+ use std:: env:: current_dir;
11
13
use std:: ffi:: { CStr , CString } ;
12
14
use std:: fmt;
13
15
use std:: hash:: Hash ;
@@ -396,9 +398,8 @@ impl Cursor {
396
398
offset : offset. try_into ( ) . unwrap ( ) ,
397
399
}
398
400
} else {
399
- let file_name = cxstring_into_string ( clang_getFileName ( file) ) ;
400
401
SourceLocation :: File {
401
- file_path : absolutize_path ( file_name ) ,
402
+ file : SourceFile :: from_raw ( file ) ,
402
403
line : line. try_into ( ) . unwrap ( ) ,
403
404
column : column. try_into ( ) . unwrap ( ) ,
404
405
offset : offset. try_into ( ) . unwrap ( ) ,
@@ -536,12 +537,8 @@ impl Cursor {
536
537
let mut children = self . collect_children ( ) ;
537
538
for child in & children {
538
539
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 ( ) ) ;
545
542
}
546
543
}
547
544
}
@@ -934,14 +931,12 @@ impl Cursor {
934
931
/// Obtain the real path name of a cursor of InclusionDirective kind.
935
932
///
936
933
/// 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 ) } ;
939
936
if file. is_null ( ) {
940
937
None
941
938
} else {
942
- Some ( unsafe {
943
- cxstring_into_string ( clang_sys:: clang_getFileName ( file) )
944
- } )
939
+ Some ( unsafe { SourceFile :: from_raw ( file) } )
945
940
}
946
941
}
947
942
}
@@ -1579,8 +1574,8 @@ pub(crate) enum SourceLocation {
1579
1574
} ,
1580
1575
/// Location in a source file.
1581
1576
File {
1582
- /// Name of the source file.
1583
- file_path : PathBuf ,
1577
+ /// The source file.
1578
+ file : SourceFile ,
1584
1579
/// Line in the source file.
1585
1580
line : usize ,
1586
1581
/// Column in the source file.
@@ -1590,18 +1585,6 @@ pub(crate) enum SourceLocation {
1590
1585
} ,
1591
1586
}
1592
1587
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
-
1605
1588
impl SourceLocation {
1606
1589
/// Locations of built-in items provided by the compiler (which don't have a source file),
1607
1590
/// are sorted first. Remaining locations are sorted by their position in the source file.
@@ -1625,59 +1608,64 @@ impl SourceLocation {
1625
1608
other. cmp_by_source_order ( self , ctx) . reverse ( )
1626
1609
}
1627
1610
(
1611
+ SourceLocation :: File { file, offset, .. } ,
1628
1612
SourceLocation :: File {
1629
- file_path, offset, ..
1630
- } ,
1631
- SourceLocation :: File {
1632
- file_path : other_file_path,
1613
+ file : other_file,
1633
1614
offset : other_offset,
1634
1615
..
1635
1616
} ,
1636
1617
) => {
1618
+ let file_path = file. path ( ) ;
1619
+ let other_file_path = other_file. path ( ) ;
1620
+
1637
1621
if file_path == other_file_path {
1638
1622
return offset. cmp ( other_offset) ;
1639
1623
}
1640
1624
1641
1625
// If `file` is transitively included via `ancestor_file`,
1642
1626
// 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 ;
1655
1648
}
1656
-
1657
- file
1658
- } else {
1659
- break ;
1660
1649
}
1661
- }
1662
1650
1663
- None
1664
- } ;
1651
+ None
1652
+ } ;
1665
1653
1666
1654
if let Some ( offset) =
1667
- offset_in_ancestor ( file_path, other_file_path)
1655
+ offset_in_ancestor ( & file_path, & other_file_path)
1668
1656
{
1669
1657
return offset. cmp ( other_offset) ;
1670
1658
}
1671
1659
1672
1660
if let Some ( other_offset) =
1673
- offset_in_ancestor ( other_file_path, file_path)
1661
+ offset_in_ancestor ( & other_file_path, & file_path)
1674
1662
{
1675
1663
return offset. cmp ( other_offset) ;
1676
1664
}
1677
1665
1678
1666
// If the source files are siblings, compare their include locations.
1679
1667
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) ;
1681
1669
parent. cmp_by_source_order ( other_parent, ctx)
1682
1670
}
1683
1671
}
@@ -1689,11 +1677,8 @@ impl fmt::Display for SourceLocation {
1689
1677
match self {
1690
1678
Self :: Builtin { .. } => "built-in" . fmt ( f) ,
1691
1679
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) ,
1697
1682
}
1698
1683
}
1699
1684
}
@@ -1803,17 +1788,63 @@ impl Iterator for CommentAttributesIterator {
1803
1788
}
1804
1789
}
1805
1790
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 {
1807
1836
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 ( )
1809
1841
}
1810
- let c_str = unsafe { CStr :: from_ptr ( clang_getCString ( s) as * const _ ) } ;
1811
- c_str. to_string_lossy ( ) . into_owned ( )
1842
+ . into_owned ( )
1812
1843
}
1813
1844
1814
- fn cxstring_into_string ( s : CXString ) -> String {
1845
+ unsafe fn cxstring_into_string ( s : CXString ) -> String {
1815
1846
let ret = cxstring_to_string_leaky ( s) ;
1816
- unsafe { clang_disposeString ( s) } ;
1847
+ clang_disposeString ( s) ;
1817
1848
ret
1818
1849
}
1819
1850
@@ -1924,13 +1955,13 @@ impl TranslationUnit {
1924
1955
}
1925
1956
}
1926
1957
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 {
1930
1961
cxstring_into_string ( clang_getTranslationUnitSpelling ( self . x ) )
1931
1962
} ;
1932
1963
1933
- absolutize_path ( file_name )
1964
+ SourceFile :: new ( name )
1934
1965
}
1935
1966
1936
1967
/// Is this the null translation unit?
0 commit comments