@@ -653,6 +653,18 @@ impl SourceMap {
653
653
} )
654
654
}
655
655
656
+ /// Extends the given `Span` while the next character matches the predicate
657
+ pub fn span_extend_while (
658
+ & self ,
659
+ span : Span ,
660
+ f : impl Fn ( char ) -> bool ,
661
+ ) -> Result < Span , SpanSnippetError > {
662
+ self . span_to_source ( span, |s, _start, end| {
663
+ let n = s[ end..] . char_indices ( ) . find ( |& ( _, c) | !f ( c) ) . map_or ( s. len ( ) - end, |( i, _) | i) ;
664
+ Ok ( span. with_hi ( span. hi ( ) + BytePos ( n as u32 ) ) )
665
+ } )
666
+ }
667
+
656
668
/// Extends the given `Span` to just after the next occurrence of `c`.
657
669
pub fn span_extend_to_next_char ( & self , sp : Span , c : char , accept_newlines : bool ) -> Span {
658
670
if let Ok ( next_source) = self . span_to_next_source ( sp) {
@@ -1013,6 +1025,32 @@ impl SourceMap {
1013
1025
let source_file = & self . files ( ) [ source_file_index] ;
1014
1026
source_file. is_imported ( )
1015
1027
}
1028
+
1029
+ /// Gets the span of a statement. If the statement is a macro expansion, the
1030
+ /// span in the context of the block span is found. The trailing semicolon is included
1031
+ /// on a best-effort basis.
1032
+ pub fn stmt_span ( & self , stmt_span : Span , block_span : Span ) -> Span {
1033
+ if !stmt_span. from_expansion ( ) {
1034
+ return stmt_span;
1035
+ }
1036
+ let mac_call = original_sp ( stmt_span, block_span) ;
1037
+ self . mac_call_stmt_semi_span ( mac_call) . map_or ( mac_call, |s| mac_call. with_hi ( s. hi ( ) ) )
1038
+ }
1039
+
1040
+ /// Tries to find the span of the semicolon of a macro call statement.
1041
+ /// The input must be the *call site* span of a statement from macro expansion.
1042
+ ///
1043
+ /// v output
1044
+ /// mac!();
1045
+ /// ^^^^^^ input
1046
+ pub fn mac_call_stmt_semi_span ( & self , mac_call : Span ) -> Option < Span > {
1047
+ let span = self . span_extend_while ( mac_call, char:: is_whitespace) . ok ( ) ?;
1048
+ let span = span. shrink_to_hi ( ) . with_hi ( BytePos ( span. hi ( ) . 0 . checked_add ( 1 ) ?) ) ;
1049
+ if self . span_to_snippet ( span) . as_deref ( ) != Ok ( ";" ) {
1050
+ return None ;
1051
+ }
1052
+ Some ( span)
1053
+ }
1016
1054
}
1017
1055
1018
1056
#[ derive( Clone ) ]
0 commit comments