@@ -610,38 +610,74 @@ impl CodeMap {
610
610
611
611
/// Returns a new span representing just the end-point of this span
612
612
pub fn end_point ( & self , sp : Span ) -> Span {
613
- let hi = sp. hi ( ) . 0 . checked_sub ( 1 ) . unwrap_or ( sp. hi ( ) . 0 ) ;
614
- let hi = self . get_start_of_char_bytepos ( BytePos ( hi) ) ;
615
- let lo = cmp:: max ( hi. 0 , sp. lo ( ) . 0 ) ;
616
- sp. with_lo ( BytePos ( lo) )
613
+ let pos = sp. hi ( ) . 0 ;
614
+
615
+ let width = self . find_width_of_character_at_span ( sp, false ) ;
616
+ let corrected_end_position = pos. checked_sub ( width) . unwrap_or ( pos) ;
617
+
618
+ let end_point = BytePos ( cmp:: max ( corrected_end_position, sp. lo ( ) . 0 ) ) ;
619
+ sp. with_lo ( end_point)
617
620
}
618
621
619
622
/// Returns a new span representing the next character after the end-point of this span
620
623
pub fn next_point ( & self , sp : Span ) -> Span {
621
- let hi = sp. lo ( ) . 0 . checked_add ( 1 ) . unwrap_or ( sp. lo ( ) . 0 ) ;
622
- let hi = self . get_start_of_char_bytepos ( BytePos ( hi) ) ;
623
- let lo = cmp:: max ( sp. hi ( ) . 0 , hi. 0 ) ;
624
- Span :: new ( BytePos ( lo) , BytePos ( lo) , sp. ctxt ( ) )
624
+ let pos = sp. lo ( ) . 0 ;
625
+
626
+ let width = self . find_width_of_character_at_span ( sp, true ) ;
627
+ let corrected_next_position = pos. checked_add ( width) . unwrap_or ( pos) ;
628
+
629
+ let next_point = BytePos ( cmp:: max ( sp. hi ( ) . 0 , corrected_next_position) ) ;
630
+ Span :: new ( next_point, next_point, sp. ctxt ( ) )
625
631
}
626
632
627
- fn get_start_of_char_bytepos ( & self , bpos : BytePos ) -> BytePos {
628
- let idx = self . lookup_filemap_idx ( bpos) ;
629
- let files = self . files . borrow ( ) ;
630
- let map = & ( * files) [ idx] ;
633
+ /// Finds the width of a character, either before or after the provided span.
634
+ fn find_width_of_character_at_span ( & self , sp : Span , forwards : bool ) -> u32 {
635
+ // Disregard malformed spans and assume a one-byte wide character.
636
+ if sp. lo ( ) > sp. hi ( ) {
637
+ return 1 ;
638
+ }
631
639
632
- for mbc in map. multibyte_chars . borrow ( ) . iter ( ) {
633
- if mbc. pos < bpos {
634
- if bpos. to_usize ( ) >= mbc. pos . to_usize ( ) + mbc. bytes {
635
- // If we do, then return the start of the character.
636
- return mbc. pos ;
637
- }
638
- } else {
639
- break ;
640
- }
640
+ let local_begin = self . lookup_byte_offset ( sp. lo ( ) ) ;
641
+ let local_end = self . lookup_byte_offset ( sp. hi ( ) ) ;
642
+
643
+ let start_index = local_begin. pos . to_usize ( ) ;
644
+ let end_index = local_end. pos . to_usize ( ) ;
645
+
646
+ // Disregard indexes that are at the start or end of their spans, they can't fit bigger
647
+ // characters.
648
+ if ( !forwards && end_index == usize:: min_value ( ) ) ||
649
+ ( forwards && start_index == usize:: max_value ( ) ) {
650
+ return 1 ;
651
+ }
652
+
653
+ let source_len = ( local_begin. fm . end_pos - local_begin. fm . start_pos ) . to_usize ( ) ;
654
+ // Ensure indexes are also not malformed.
655
+ if start_index > end_index || end_index > source_len {
656
+ return 1 ;
641
657
}
642
658
643
- // If this isn't a multibyte character, return the original position.
644
- return bpos;
659
+ // We need to extend the snippet to the end of the src rather than to end_index so when
660
+ // searching forwards for boundaries we've got somewhere to search.
661
+ let snippet = if let Some ( ref src) = local_begin. fm . src {
662
+ let len = src. len ( ) ;
663
+ ( & src[ start_index..len] ) . to_string ( )
664
+ } else if let Some ( src) = local_begin. fm . external_src . borrow ( ) . get_source ( ) {
665
+ let len = src. len ( ) ;
666
+ ( & src[ start_index..len] ) . to_string ( )
667
+ } else {
668
+ return 1 ;
669
+ } ;
670
+
671
+ let mut target = if forwards { end_index + 1 } else { end_index - 1 } ;
672
+ while !snippet. is_char_boundary ( target - start_index) {
673
+ target = if forwards { target + 1 } else { target - 1 } ;
674
+ }
675
+
676
+ if forwards {
677
+ ( target - end_index) as u32
678
+ } else {
679
+ ( end_index - target) as u32
680
+ }
645
681
}
646
682
647
683
pub fn get_filemap ( & self , filename : & FileName ) -> Option < Rc < FileMap > > {
0 commit comments