@@ -839,6 +839,8 @@ pub struct RemappedFrameIter<'r, 'data> {
839839 had_mappings : bool ,
840840 /// Whether this method has any line-based mappings.
841841 has_line_info : bool ,
842+ /// Whether any frame was successfully matched by iterate_with_lines.
843+ matched_any : bool ,
842844 /// The source file of the outer class for synthesis.
843845 outer_source_file : Option < & ' data str > ,
844846}
@@ -852,6 +854,7 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
852854 skip_count : 0 ,
853855 had_mappings : false ,
854856 has_line_info : false ,
857+ matched_any : false ,
855858 outer_source_file : None ,
856859 }
857860 }
@@ -872,6 +875,7 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
872875 skip_count,
873876 had_mappings,
874877 has_line_info,
878+ matched_any : false ,
875879 outer_source_file,
876880 }
877881 }
@@ -884,6 +888,7 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
884888 skip_count : 0 ,
885889 had_mappings : false ,
886890 has_line_info : false ,
891+ matched_any : false ,
887892 outer_source_file : None ,
888893 }
889894 }
@@ -933,9 +938,20 @@ impl<'r, 'data> RemappedFrameIter<'r, 'data> {
933938 & mut members,
934939 self . outer_source_file ,
935940 self . has_line_info ,
941+ & mut self . pending_frames ,
936942 ) ;
937- self . inner = Some ( ( cache, frame, members) ) ;
938- mapped
943+ if mapped. is_some ( ) {
944+ self . matched_any = true ;
945+ self . inner = Some ( ( cache, frame, members) ) ;
946+ mapped
947+ } else if !self . matched_any && self . has_line_info {
948+ // Outside-range fallback: no member matched the frame line.
949+ // Remap only the class name, keeping the obfuscated method name
950+ // and the original line.
951+ Some ( cache. remap_class_only ( & frame, self . outer_source_file ) )
952+ } else {
953+ None
954+ }
939955 } else {
940956 let mapped =
941957 iterate_without_lines ( cache, & mut frame, & mut members, self . outer_source_file ) ;
@@ -966,6 +982,7 @@ fn iterate_with_lines<'a>(
966982 members : & mut std:: slice:: Iter < ' _ , raw:: Member > ,
967983 outer_source_file : Option < & str > ,
968984 has_line_info : bool ,
985+ pending_frames : & mut Vec < StackFrame < ' a > > ,
969986) -> Option < StackFrame < ' a > > {
970987 let frame_line = frame. line . unwrap_or ( 0 ) ;
971988 for member in members {
@@ -975,10 +992,42 @@ fn iterate_with_lines<'a>(
975992 }
976993 // If the mapping entry has no line range, determine output line.
977994 if member. endline ( ) . unwrap_or ( 0 ) == 0 {
978- let output_line = if member. original_startline ( ) . is_none ( ) {
995+ if member. original_startline ( ) . is_none ( ) {
979996 // Bare method mapping: pass through frame line.
980- frame. line
981- } else if member. original_startline ( ) . unwrap_or ( 0 ) > 0 {
997+ return map_member_without_lines (
998+ cache,
999+ frame,
1000+ member,
1001+ outer_source_file,
1002+ frame. line ,
1003+ ) ;
1004+ }
1005+ // Span expansion: if the original range spans multiple lines,
1006+ // emit one frame per original line.
1007+ if member. original_endline != u32:: MAX
1008+ && member. original_endline > member. original_startline ( ) . unwrap_or ( 0 ) as u32
1009+ {
1010+ let first_line = member. original_startline ( ) . unwrap_or ( 0 ) as usize ;
1011+ let last_line = member. original_endline as usize ;
1012+ let mut first_frame = None ;
1013+ for line in first_line..=last_line {
1014+ if let Some ( f) = map_member_without_lines (
1015+ cache,
1016+ frame,
1017+ member,
1018+ outer_source_file,
1019+ Some ( line) ,
1020+ ) {
1021+ if first_frame. is_none ( ) {
1022+ first_frame = Some ( f) ;
1023+ } else {
1024+ pending_frames. push ( f) ;
1025+ }
1026+ }
1027+ }
1028+ return first_frame;
1029+ }
1030+ let output_line = if member. original_startline ( ) . unwrap_or ( 0 ) > 0 {
9821031 Some ( member. original_startline ( ) . unwrap_or ( 0 ) as usize )
9831032 } else {
9841033 None
0 commit comments