@@ -221,6 +221,10 @@ impl FileMap {
221
221
// UNCHECKED INVARIANT: these offsets must be added in the right
222
222
// order and must be in the right places; there is shared knowledge
223
223
// 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.
224
228
pub fn next_line ( & self , pos : BytePos ) {
225
229
// the new charpos must be > the last one (or it's the first one).
226
230
let mut lines = self . lines . borrow_mut ( ) ; ;
@@ -267,13 +271,21 @@ impl CodeMap {
267
271
}
268
272
}
269
273
270
- pub fn new_filemap ( & self , filename : FileName , src : ~str ) -> @FileMap {
274
+ pub fn new_filemap ( & self , filename : FileName , mut src : ~str ) -> @FileMap {
271
275
let mut files = self . files . borrow_mut ( ) ;
272
276
let start_pos = match files. get ( ) . last ( ) {
273
277
None => 0 ,
274
278
Some ( last) => last. start_pos . to_uint ( ) + last. src . len ( ) ,
275
279
} ;
276
280
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
+
277
289
let filemap = @FileMap {
278
290
name : filename,
279
291
src : src,
@@ -510,9 +522,9 @@ mod test {
510
522
511
523
fm1.next_line(BytePos(0));
512
524
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 ));
516
528
517
529
cm
518
530
}
@@ -526,7 +538,7 @@ mod test {
526
538
assert_eq!(fmabp1.fm.name, ~" blork. rs");
527
539
assert_eq!(fmabp1.pos, BytePos(22));
528
540
529
- let fmabp2 = cm.lookup_byte_offset(BytePos(23 ));
541
+ let fmabp2 = cm.lookup_byte_offset(BytePos(24 ));
530
542
assert_eq!(fmabp2.fm.name, ~" blork2. rs");
531
543
assert_eq!(fmabp2.pos, BytePos(0));
532
544
}
@@ -539,7 +551,7 @@ mod test {
539
551
let cp1 = cm.bytepos_to_file_charpos(BytePos(22));
540
552
assert_eq!(cp1, CharPos(22));
541
553
542
- let cp2 = cm.bytepos_to_file_charpos(BytePos(23 ));
554
+ let cp2 = cm.bytepos_to_file_charpos(BytePos(24 ));
543
555
assert_eq!(cp2, CharPos(0));
544
556
}
545
557
@@ -553,7 +565,7 @@ mod test {
553
565
assert_eq!(loc1.line, 2);
554
566
assert_eq!(loc1.col, CharPos(10));
555
567
556
- let loc2 = cm.lookup_char_pos(BytePos(23 ));
568
+ let loc2 = cm.lookup_char_pos(BytePos(24 ));
557
569
assert_eq!(loc2.file.name, ~" blork2. rs");
558
570
assert_eq!(loc2.line, 1);
559
571
assert_eq!(loc2.col, CharPos(0));
@@ -567,17 +579,17 @@ mod test {
567
579
568
580
fm1.next_line(BytePos(0));
569
581
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 ));
572
584
573
585
fm1.record_multibyte_char(BytePos(3), 3);
574
586
fm1.record_multibyte_char(BytePos(9), 3);
575
587
fm1.record_multibyte_char(BytePos(12), 3);
576
588
fm1.record_multibyte_char(BytePos(15), 3);
577
589
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);
581
593
582
594
cm
583
595
}
@@ -593,10 +605,42 @@ mod test {
593
605
let cp2 = cm.bytepos_to_file_charpos(BytePos(6));
594
606
assert_eq!(cp2, CharPos(4));
595
607
596
- let cp3 = cm. bytepos_to_file_charpos ( BytePos ( 55 ) ) ;
608
+ let cp3 = cm.bytepos_to_file_charpos(BytePos(56 ));
597
609
assert_eq!(cp3, CharPos(12));
598
610
599
- let cp4 = cm. bytepos_to_file_charpos ( BytePos ( 60 ) ) ;
611
+ let cp4 = cm.bytepos_to_file_charpos(BytePos(61 ));
600
612
assert_eq!(cp4, CharPos(15));
601
613
}
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
+ }
602
646
}
0 commit comments