@@ -25,6 +25,7 @@ pub use self::ExpnFormat::*;
25
25
use rustc_data_structures:: fx:: FxHashMap ;
26
26
use rustc_data_structures:: stable_hasher:: StableHasher ;
27
27
use std:: cell:: { RefCell , Ref } ;
28
+ use std:: cmp;
28
29
use std:: hash:: Hash ;
29
30
use std:: path:: { Path , PathBuf } ;
30
31
use std:: rc:: Rc ;
@@ -607,6 +608,87 @@ impl CodeMap {
607
608
self . span_until_char ( sp, '{' )
608
609
}
609
610
611
+ /// Returns a new span representing just the end-point of this span
612
+ pub fn end_point ( & self , sp : Span ) -> Span {
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)
620
+ }
621
+
622
+ /// Returns a new span representing the next character after the end-point of this span
623
+ pub fn next_point ( & self , sp : Span ) -> Span {
624
+ let start_of_next_point = sp. hi ( ) . 0 ;
625
+
626
+ let width = self . find_width_of_character_at_span ( sp, true ) ;
627
+ // If the width is 1, then the next span should point to the same `lo` and `hi`. However,
628
+ // in the case of a multibyte character, where the width != 1, the next span should
629
+ // span multiple bytes to include the whole character.
630
+ let end_of_next_point = start_of_next_point. checked_add (
631
+ width - 1 ) . unwrap_or ( start_of_next_point) ;
632
+
633
+ let end_of_next_point = BytePos ( cmp:: max ( sp. lo ( ) . 0 + 1 , end_of_next_point) ) ;
634
+ Span :: new ( BytePos ( start_of_next_point) , end_of_next_point, sp. ctxt ( ) )
635
+ }
636
+
637
+ /// Finds the width of a character, either before or after the provided span.
638
+ fn find_width_of_character_at_span ( & self , sp : Span , forwards : bool ) -> u32 {
639
+ // Disregard malformed spans and assume a one-byte wide character.
640
+ if sp. lo ( ) >= sp. hi ( ) {
641
+ return 1 ;
642
+ }
643
+
644
+ let local_begin = self . lookup_byte_offset ( sp. lo ( ) ) ;
645
+ let local_end = self . lookup_byte_offset ( sp. hi ( ) ) ;
646
+
647
+ let start_index = local_begin. pos . to_usize ( ) ;
648
+ let end_index = local_end. pos . to_usize ( ) ;
649
+
650
+ // Disregard indexes that are at the start or end of their spans, they can't fit bigger
651
+ // characters.
652
+ if ( !forwards && end_index == usize:: min_value ( ) ) ||
653
+ ( forwards && start_index == usize:: max_value ( ) ) {
654
+ return 1 ;
655
+ }
656
+
657
+ let source_len = ( local_begin. fm . end_pos - local_begin. fm . start_pos ) . to_usize ( ) ;
658
+ // Ensure indexes are also not malformed.
659
+ if start_index > end_index || end_index > source_len {
660
+ return 1 ;
661
+ }
662
+
663
+ // We need to extend the snippet to the end of the src rather than to end_index so when
664
+ // searching forwards for boundaries we've got somewhere to search.
665
+ let snippet = if let Some ( ref src) = local_begin. fm . src {
666
+ let len = src. len ( ) ;
667
+ ( & src[ start_index..len] ) . to_string ( )
668
+ } else if let Some ( src) = local_begin. fm . external_src . borrow ( ) . get_source ( ) {
669
+ let len = src. len ( ) ;
670
+ ( & src[ start_index..len] ) . to_string ( )
671
+ } else {
672
+ return 1 ;
673
+ } ;
674
+ debug ! ( "DTW start {:?} end {:?}" , start_index, end_index) ;
675
+ debug ! ( "DTW snippet {:?}" , snippet) ;
676
+
677
+ let mut target = if forwards { end_index + 1 } else { end_index - 1 } ;
678
+ debug ! ( "DTW initial target {:?}" , target) ;
679
+ while !snippet. is_char_boundary ( target - start_index) {
680
+ target = if forwards { target + 1 } else { target - 1 } ;
681
+ debug ! ( "DTW update target {:?}" , target) ;
682
+ }
683
+ debug ! ( "DTW final target {:?}" , target) ;
684
+
685
+ if forwards {
686
+ ( target - end_index) as u32
687
+ } else {
688
+ ( end_index - target) as u32
689
+ }
690
+ }
691
+
610
692
pub fn get_filemap ( & self , filename : & FileName ) -> Option < Rc < FileMap > > {
611
693
for fm in self . files . borrow ( ) . iter ( ) {
612
694
if * filename == fm. name {
0 commit comments