@@ -766,18 +766,11 @@ fn text_has_safety_comment(
766766 start_pos : BytePos ,
767767 accept_comment_above_attributes : bool ,
768768) -> HasSafetyComment {
769- let mut lines = line_starts
770- . array_windows :: < 2 > ( )
771- . rev ( )
772- . map_while ( |[ start, end] | {
773- let start = start. to_usize ( ) ;
774- let end = end. to_usize ( ) ;
775- let text = src. get ( start..end) ?;
776- let trimmed = text. trim_start ( ) ;
777- Some ( ( start + ( text. len ( ) - trimmed. len ( ) ) , trimmed) )
778- } )
779- . filter ( |( _, text) | !( text. is_empty ( ) || ( accept_comment_above_attributes && is_attribute ( text) ) ) ) ;
780-
769+ let mut lines: Box < dyn Iterator < Item = ( usize , & str ) > > = if accept_comment_above_attributes {
770+ Box :: new ( reversed_lines_skipping_attributes ( src, line_starts) )
771+ } else {
772+ Box :: new ( reversed_lines ( src, line_starts) )
773+ } ;
781774 let Some ( ( line_start, line) ) = lines. next ( ) else {
782775 return HasSafetyComment :: No ;
783776 } ;
@@ -835,8 +828,55 @@ fn text_has_safety_comment(
835828 }
836829}
837830
838- fn is_attribute ( text : & str ) -> bool {
839- ( text. starts_with ( "#[" ) || text. starts_with ( "#![" ) ) && text. trim_end ( ) . ends_with ( ']' )
831+ fn reversed_lines_skipping_attributes < ' a > (
832+ src : & ' a str ,
833+ line_starts : & ' a [ RelativeBytePos ] ,
834+ ) -> impl Iterator < Item = ( usize , & ' a str ) > + ' a {
835+ let lines = line_starts
836+ . array_windows :: < 2 > ( )
837+ . filter_map ( |[ start, end] | process_line ( src, * start, * end) ) ;
838+
839+ let mut buffer = vec ! [ ] ;
840+ let mut in_attribute = false ;
841+ for ( start, text) in lines {
842+ if in_attribute {
843+ in_attribute = !is_attribute_end ( text) ;
844+ } else if is_attribute_start ( text) {
845+ if !is_attribute_end ( text) {
846+ in_attribute = true ;
847+ }
848+ } else {
849+ buffer. push ( ( start, text) ) ;
850+ }
851+ }
852+ buffer. into_iter ( ) . rev ( )
853+ }
854+
855+ fn is_attribute_start ( text : & str ) -> bool {
856+ text. starts_with ( "#[" ) || text. starts_with ( "#![" )
857+ }
858+
859+ fn is_attribute_end ( text : & str ) -> bool {
860+ text. trim_end ( ) . ends_with ( ']' )
861+ }
862+
863+ fn reversed_lines < ' a > ( src : & ' a str , line_starts : & ' a [ RelativeBytePos ] ) -> impl Iterator < Item = ( usize , & ' a str ) > + ' a {
864+ line_starts
865+ . array_windows :: < 2 > ( )
866+ . rev ( )
867+ . filter_map ( |[ start, end] | process_line ( src, * start, * end) )
868+ }
869+
870+ fn process_line ( src : & str , start : RelativeBytePos , end : RelativeBytePos ) -> Option < ( usize , & str ) > {
871+ let start_idx = start. to_usize ( ) ;
872+ let end_idx = end. to_usize ( ) ;
873+ let text = src. get ( start_idx..end_idx) ?;
874+ let trimmed = text. trim_start ( ) ;
875+ if trimmed. is_empty ( ) {
876+ None
877+ } else {
878+ Some ( ( start_idx + ( text. len ( ) - trimmed. len ( ) ) , trimmed) )
879+ }
840880}
841881
842882fn span_and_hid_of_item_alike_node ( node : & Node < ' _ > ) -> Option < ( Span , HirId ) > {
0 commit comments