@@ -21,10 +21,11 @@ pub use self::ExpnFormat::*;
2121
2222use std:: cell:: { Cell , RefCell } ;
2323use std:: ops:: { Add , Sub } ;
24- use std:: path:: Path ;
24+ use std:: path:: { Path , PathBuf } ;
2525use std:: rc:: Rc ;
2626use std:: cmp;
2727
28+ use std:: env;
2829use std:: { fmt, fs} ;
2930use std:: io:: { self , Read } ;
3031
@@ -508,6 +509,8 @@ pub struct FileMap {
508509 /// originate from files has names between angle brackets by convention,
509510 /// e.g. `<anon>`
510511 pub name : FileName ,
512+ /// The absolute path of the file that the source came from.
513+ pub abs_path : Option < FileName > ,
511514 /// The complete source code
512515 pub src : Option < Rc < String > > ,
513516 /// The start position of this source in the CodeMap
@@ -522,11 +525,12 @@ pub struct FileMap {
522525
523526impl Encodable for FileMap {
524527 fn encode < S : Encoder > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > {
525- s. emit_struct ( "FileMap" , 5 , |s| {
528+ s. emit_struct ( "FileMap" , 6 , |s| {
526529 s. emit_struct_field ( "name" , 0 , |s| self . name . encode ( s) ) ?;
527- s. emit_struct_field ( "start_pos" , 1 , |s| self . start_pos . encode ( s) ) ?;
528- s. emit_struct_field ( "end_pos" , 2 , |s| self . end_pos . encode ( s) ) ?;
529- s. emit_struct_field ( "lines" , 3 , |s| {
530+ s. emit_struct_field ( "abs_path" , 1 , |s| self . abs_path . encode ( s) ) ?;
531+ s. emit_struct_field ( "start_pos" , 2 , |s| self . start_pos . encode ( s) ) ?;
532+ s. emit_struct_field ( "end_pos" , 3 , |s| self . end_pos . encode ( s) ) ?;
533+ s. emit_struct_field ( "lines" , 4 , |s| {
530534 let lines = self . lines . borrow ( ) ;
531535 // store the length
532536 s. emit_u32 ( lines. len ( ) as u32 ) ?;
@@ -572,7 +576,7 @@ impl Encodable for FileMap {
572576
573577 Ok ( ( ) )
574578 } ) ?;
575- s. emit_struct_field ( "multibyte_chars" , 4 , |s| {
579+ s. emit_struct_field ( "multibyte_chars" , 5 , |s| {
576580 ( * self . multibyte_chars . borrow ( ) ) . encode ( s)
577581 } )
578582 } )
@@ -582,11 +586,13 @@ impl Encodable for FileMap {
582586impl Decodable for FileMap {
583587 fn decode < D : Decoder > ( d : & mut D ) -> Result < FileMap , D :: Error > {
584588
585- d. read_struct ( "FileMap" , 5 , |d| {
589+ d. read_struct ( "FileMap" , 6 , |d| {
586590 let name: String = d. read_struct_field ( "name" , 0 , |d| Decodable :: decode ( d) ) ?;
587- let start_pos: BytePos = d. read_struct_field ( "start_pos" , 1 , |d| Decodable :: decode ( d) ) ?;
588- let end_pos: BytePos = d. read_struct_field ( "end_pos" , 2 , |d| Decodable :: decode ( d) ) ?;
589- let lines: Vec < BytePos > = d. read_struct_field ( "lines" , 3 , |d| {
591+ let abs_path: Option < String > =
592+ d. read_struct_field ( "abs_path" , 1 , |d| Decodable :: decode ( d) ) ?;
593+ let start_pos: BytePos = d. read_struct_field ( "start_pos" , 2 , |d| Decodable :: decode ( d) ) ?;
594+ let end_pos: BytePos = d. read_struct_field ( "end_pos" , 3 , |d| Decodable :: decode ( d) ) ?;
595+ let lines: Vec < BytePos > = d. read_struct_field ( "lines" , 4 , |d| {
590596 let num_lines: u32 = Decodable :: decode ( d) ?;
591597 let mut lines = Vec :: with_capacity ( num_lines as usize ) ;
592598
@@ -615,9 +621,10 @@ impl Decodable for FileMap {
615621 Ok ( lines)
616622 } ) ?;
617623 let multibyte_chars: Vec < MultiByteChar > =
618- d. read_struct_field ( "multibyte_chars" , 4 , |d| Decodable :: decode ( d) ) ?;
624+ d. read_struct_field ( "multibyte_chars" , 5 , |d| Decodable :: decode ( d) ) ?;
619625 Ok ( FileMap {
620626 name : name,
627+ abs_path : abs_path,
621628 start_pos : start_pos,
622629 end_pos : end_pos,
623630 src : None ,
@@ -703,6 +710,9 @@ pub trait FileLoader {
703710 /// Query the existence of a file.
704711 fn file_exists ( & self , path : & Path ) -> bool ;
705712
713+ /// Return an absolute path to a file, if possible.
714+ fn abs_path ( & self , path : & Path ) -> Option < PathBuf > ;
715+
706716 /// Read the contents of an UTF-8 file into memory.
707717 fn read_file ( & self , path : & Path ) -> io:: Result < String > ;
708718}
@@ -715,6 +725,16 @@ impl FileLoader for RealFileLoader {
715725 fs:: metadata ( path) . is_ok ( )
716726 }
717727
728+ fn abs_path ( & self , path : & Path ) -> Option < PathBuf > {
729+ if path. is_absolute ( ) {
730+ Some ( path. to_path_buf ( ) )
731+ } else {
732+ env:: current_dir ( )
733+ . ok ( )
734+ . map ( |cwd| cwd. join ( path) )
735+ }
736+ }
737+
718738 fn read_file ( & self , path : & Path ) -> io:: Result < String > {
719739 let mut src = String :: new ( ) ;
720740 fs:: File :: open ( path) ?. read_to_string ( & mut src) ?;
@@ -755,7 +775,8 @@ impl CodeMap {
755775
756776 pub fn load_file ( & self , path : & Path ) -> io:: Result < Rc < FileMap > > {
757777 let src = self . file_loader . read_file ( path) ?;
758- Ok ( self . new_filemap ( path. to_str ( ) . unwrap ( ) . to_string ( ) , src) )
778+ let abs_path = self . file_loader . abs_path ( path) . map ( |p| p. to_str ( ) . unwrap ( ) . to_string ( ) ) ;
779+ Ok ( self . new_filemap ( path. to_str ( ) . unwrap ( ) . to_string ( ) , abs_path, src) )
759780 }
760781
761782 fn next_start_pos ( & self ) -> usize {
@@ -770,7 +791,8 @@ impl CodeMap {
770791
771792 /// Creates a new filemap without setting its line information. If you don't
772793 /// intend to set the line information yourself, you should use new_filemap_and_lines.
773- pub fn new_filemap ( & self , filename : FileName , mut src : String ) -> Rc < FileMap > {
794+ pub fn new_filemap ( & self , filename : FileName , abs_path : Option < FileName > ,
795+ mut src : String ) -> Rc < FileMap > {
774796 let start_pos = self . next_start_pos ( ) ;
775797 let mut files = self . files . borrow_mut ( ) ;
776798
@@ -783,6 +805,7 @@ impl CodeMap {
783805
784806 let filemap = Rc :: new ( FileMap {
785807 name : filename,
808+ abs_path : abs_path,
786809 src : Some ( Rc :: new ( src) ) ,
787810 start_pos : Pos :: from_usize ( start_pos) ,
788811 end_pos : Pos :: from_usize ( end_pos) ,
@@ -796,8 +819,11 @@ impl CodeMap {
796819 }
797820
798821 /// Creates a new filemap and sets its line information.
799- pub fn new_filemap_and_lines ( & self , filename : & str , src : & str ) -> Rc < FileMap > {
800- let fm = self . new_filemap ( filename. to_string ( ) , src. to_owned ( ) ) ;
822+ pub fn new_filemap_and_lines ( & self , filename : & str , abs_path : Option < & str > ,
823+ src : & str ) -> Rc < FileMap > {
824+ let fm = self . new_filemap ( filename. to_string ( ) ,
825+ abs_path. map ( |s| s. to_owned ( ) ) ,
826+ src. to_owned ( ) ) ;
801827 let mut byte_pos: u32 = fm. start_pos . 0 ;
802828 for line in src. lines ( ) {
803829 // register the start of this line
@@ -816,6 +842,7 @@ impl CodeMap {
816842 /// information for things inlined from other crates.
817843 pub fn new_imported_filemap ( & self ,
818844 filename : FileName ,
845+ abs_path : Option < FileName > ,
819846 source_len : usize ,
820847 mut file_local_lines : Vec < BytePos > ,
821848 mut file_local_multibyte_chars : Vec < MultiByteChar > )
@@ -836,6 +863,7 @@ impl CodeMap {
836863
837864 let filemap = Rc :: new ( FileMap {
838865 name : filename,
866+ abs_path : abs_path,
839867 src : None ,
840868 start_pos : start_pos,
841869 end_pos : end_pos,
@@ -1422,6 +1450,7 @@ mod tests {
14221450 fn t1 ( ) {
14231451 let cm = CodeMap :: new ( ) ;
14241452 let fm = cm. new_filemap ( "blork.rs" . to_string ( ) ,
1453+ None ,
14251454 "first line.\n second line" . to_string ( ) ) ;
14261455 fm. next_line ( BytePos ( 0 ) ) ;
14271456 // Test we can get lines with partial line info.
@@ -1438,6 +1467,7 @@ mod tests {
14381467 fn t2 ( ) {
14391468 let cm = CodeMap :: new ( ) ;
14401469 let fm = cm. new_filemap ( "blork.rs" . to_string ( ) ,
1470+ None ,
14411471 "first line.\n second line" . to_string ( ) ) ;
14421472 // TESTING *REALLY* BROKEN BEHAVIOR:
14431473 fm. next_line ( BytePos ( 0 ) ) ;
@@ -1448,10 +1478,13 @@ mod tests {
14481478 fn init_code_map ( ) -> CodeMap {
14491479 let cm = CodeMap :: new ( ) ;
14501480 let fm1 = cm. new_filemap ( "blork.rs" . to_string ( ) ,
1481+ None ,
14511482 "first line.\n second line" . to_string ( ) ) ;
14521483 let fm2 = cm. new_filemap ( "empty.rs" . to_string ( ) ,
1484+ None ,
14531485 "" . to_string ( ) ) ;
14541486 let fm3 = cm. new_filemap ( "blork2.rs" . to_string ( ) ,
1487+ None ,
14551488 "first line.\n second line" . to_string ( ) ) ;
14561489
14571490 fm1. next_line ( BytePos ( 0 ) ) ;
@@ -1514,8 +1547,10 @@ mod tests {
15141547 // € is a three byte utf8 char.
15151548 let fm1 =
15161549 cm. new_filemap ( "blork.rs" . to_string ( ) ,
1550+ None ,
15171551 "fir€st €€€€ line.\n second line" . to_string ( ) ) ;
15181552 let fm2 = cm. new_filemap ( "blork2.rs" . to_string ( ) ,
1553+ None ,
15191554 "first line€€.\n € second line" . to_string ( ) ) ;
15201555
15211556 fm1. next_line ( BytePos ( 0 ) ) ;
@@ -1583,7 +1618,7 @@ mod tests {
15831618 let cm = CodeMap :: new ( ) ;
15841619 let inputtext = "aaaaa\n bbbbBB\n CCC\n DDDDDddddd\n eee\n " ;
15851620 let selection = " \n ~~\n ~~~\n ~~~~~ \n \n " ;
1586- cm. new_filemap_and_lines ( "blork.rs" , inputtext) ;
1621+ cm. new_filemap_and_lines ( "blork.rs" , None , inputtext) ;
15871622 let span = span_from_selection ( inputtext, selection) ;
15881623
15891624 // check that we are extracting the text we thought we were extracting
0 commit comments