@@ -221,6 +221,10 @@ impl FileMap {
221221 // UNCHECKED INVARIANT: these offsets must be added in the right
222222 // order and must be in the right places; there is shared knowledge
223223 // about what ends a line between this file and parse.rs
224+ // WARNING: pos param here is the offset relative to start of CodeMap,
225+ // and CodeMap will append a newline when adding a filemap without a newline at the end,
226+ // so the safe way to call this is with value calculated as
227+ // filemap.start_pos + newline_offset_relative_to_the_start_of_filemap.
224228 pub fn next_line ( & self , pos : BytePos ) {
225229 // the new charpos must be > the last one (or it's the first one).
226230 let mut lines = self . lines . borrow_mut ( ) ; ;
@@ -267,13 +271,21 @@ impl CodeMap {
267271 }
268272 }
269273
270- pub fn new_filemap ( & self , filename : FileName , src : ~str ) -> @FileMap {
274+ pub fn new_filemap ( & self , filename : FileName , mut src : ~str ) -> @FileMap {
271275 let mut files = self . files . borrow_mut ( ) ;
272276 let start_pos = match files. get ( ) . last ( ) {
273277 None => 0 ,
274278 Some ( last) => last. start_pos . to_uint ( ) + last. src . len ( ) ,
275279 } ;
276280
281+ // Append '\n' in case it's not already there.
282+ // This is a workaround to prevent CodeMap.lookup_filemap_idx from accidentally
283+ // overflowing into the next filemap in case the last byte of span is also the last
284+ // byte of filemap, which leads to incorrect results from CodeMap.span_to_*.
285+ if src. len ( ) > 0 && !src. ends_with ( "\n " ) {
286+ src. push_char ( '\n' ) ;
287+ }
288+
277289 let filemap = @FileMap {
278290 name : filename,
279291 src : src,
@@ -510,9 +522,9 @@ mod test {
510522
511523 fm1.next_line(BytePos(0));
512524 fm1.next_line(BytePos(12));
513- fm2.next_line(BytePos(23 ));
514- fm3.next_line(BytePos(23 ));
515- fm3.next_line(BytePos(33 ));
525+ fm2.next_line(BytePos(24 ));
526+ fm3.next_line(BytePos(24 ));
527+ fm3.next_line(BytePos(34 ));
516528
517529 cm
518530 }
@@ -526,7 +538,7 @@ mod test {
526538 assert_eq!(fmabp1.fm.name, ~" blork. rs");
527539 assert_eq!(fmabp1.pos, BytePos(22));
528540
529- let fmabp2 = cm.lookup_byte_offset(BytePos(23 ));
541+ let fmabp2 = cm.lookup_byte_offset(BytePos(24 ));
530542 assert_eq!(fmabp2.fm.name, ~" blork2. rs");
531543 assert_eq!(fmabp2.pos, BytePos(0));
532544 }
@@ -539,7 +551,7 @@ mod test {
539551 let cp1 = cm.bytepos_to_file_charpos(BytePos(22));
540552 assert_eq!(cp1, CharPos(22));
541553
542- let cp2 = cm.bytepos_to_file_charpos(BytePos(23 ));
554+ let cp2 = cm.bytepos_to_file_charpos(BytePos(24 ));
543555 assert_eq!(cp2, CharPos(0));
544556 }
545557
@@ -553,7 +565,7 @@ mod test {
553565 assert_eq!(loc1.line, 2);
554566 assert_eq!(loc1.col, CharPos(10));
555567
556- let loc2 = cm.lookup_char_pos(BytePos(23 ));
568+ let loc2 = cm.lookup_char_pos(BytePos(24 ));
557569 assert_eq!(loc2.file.name, ~" blork2. rs");
558570 assert_eq!(loc2.line, 1);
559571 assert_eq!(loc2.col, CharPos(0));
@@ -567,17 +579,17 @@ mod test {
567579
568580 fm1.next_line(BytePos(0));
569581 fm1.next_line(BytePos(22));
570- fm2. next_line ( BytePos ( 39 ) ) ;
571- fm2. next_line ( BytePos ( 57 ) ) ;
582+ fm2.next_line(BytePos(40 ));
583+ fm2.next_line(BytePos(58 ));
572584
573585 fm1.record_multibyte_char(BytePos(3), 3);
574586 fm1.record_multibyte_char(BytePos(9), 3);
575587 fm1.record_multibyte_char(BytePos(12), 3);
576588 fm1.record_multibyte_char(BytePos(15), 3);
577589 fm1.record_multibyte_char(BytePos(18), 3);
578- fm2. record_multibyte_char ( BytePos ( 49 ) , 3 ) ;
579- fm2. record_multibyte_char ( BytePos ( 52 ) , 3 ) ;
580- fm2. record_multibyte_char ( BytePos ( 57 ) , 3 ) ;
590+ fm2.record_multibyte_char(BytePos(50 ), 3);
591+ fm2.record_multibyte_char(BytePos(53 ), 3);
592+ fm2.record_multibyte_char(BytePos(58 ), 3);
581593
582594 cm
583595 }
@@ -593,10 +605,42 @@ mod test {
593605 let cp2 = cm.bytepos_to_file_charpos(BytePos(6));
594606 assert_eq!(cp2, CharPos(4));
595607
596- let cp3 = cm. bytepos_to_file_charpos ( BytePos ( 55 ) ) ;
608+ let cp3 = cm.bytepos_to_file_charpos(BytePos(56 ));
597609 assert_eq!(cp3, CharPos(12));
598610
599- let cp4 = cm. bytepos_to_file_charpos ( BytePos ( 60 ) ) ;
611+ let cp4 = cm.bytepos_to_file_charpos(BytePos(61 ));
600612 assert_eq!(cp4, CharPos(15));
601613 }
614+
615+ #[test]
616+ fn t7() {
617+ // Test span_to_lines for a span ending at the end of filemap
618+ let cm = init_code_map();
619+ let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
620+ let file_lines = cm.span_to_lines(span);
621+
622+ assert_eq!(file_lines.file.name, ~" blork. rs");
623+ assert_eq!(file_lines.lines.len(), 1);
624+ assert_eq!(*file_lines.lines.get(0), 1u);
625+ }
626+
627+ #[test]
628+ fn t8() {
629+ // Test span_to_snippet for a span ending at the end of filemap
630+ let cm = init_code_map();
631+ let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
632+ let snippet = cm.span_to_snippet(span);
633+
634+ assert_eq!(snippet, Some(~" second line"));
635+ }
636+
637+ #[test]
638+ fn t9() {
639+ // Test span_to_str for a span ending at the end of filemap
640+ let cm = init_code_map();
641+ let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
642+ let sstr = cm.span_to_str(span);
643+
644+ assert_eq!(sstr, ~" blork. rs: 2 : 1 : 2 : 12 " ) ;
645+ }
602646}
0 commit comments