@@ -34,7 +34,7 @@ pub enum ParseError {
34
34
/// This function will take a **mangled** symbol and return a value. When printed,
35
35
/// the de-mangled version will be written. If the symbol does not look like
36
36
/// a mangled symbol, the original value will be written instead.
37
- pub fn demangle ( s : & str ) -> Result < ( Demangle , & str ) , ParseError > {
37
+ pub fn demangle ( s : & str ) -> Result < ( Demangle < ' _ > , & str ) , ParseError > {
38
38
// First validate the symbol. If it doesn't look like anything we're
39
39
// expecting, we just print it literally. Note that we must handle non-Rust
40
40
// symbols because we could have any function in the backtrace.
@@ -91,7 +91,7 @@ pub fn demangle(s: &str) -> Result<(Demangle, &str), ParseError> {
91
91
}
92
92
93
93
impl < ' s > fmt:: Display for Demangle < ' s > {
94
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
94
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
95
95
let mut printer = Printer {
96
96
parser : Ok ( Parser {
97
97
sym : self . inner ,
@@ -238,7 +238,7 @@ impl<'s> Ident<'s> {
238
238
}
239
239
240
240
impl < ' s > fmt:: Display for Ident < ' s > {
241
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
241
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
242
242
self . try_small_punycode_decode ( |chars| {
243
243
for & c in chars {
244
244
c. fmt ( f) ?;
@@ -563,9 +563,57 @@ impl<'s> Parser<'s> {
563
563
} )
564
564
}
565
565
}
566
+
567
+ /// Looks for the `C<digits>_` prefix that marks a skippable section.
568
+ fn peek_skippable_prefix ( & self ) -> Option < SkippableSection > {
569
+ let bytes = self . sym . as_bytes ( ) ;
570
+ let mut index = self . next ;
571
+
572
+ if bytes. get ( index) . cloned ( ) != Some ( b'C' ) {
573
+ return None ;
574
+ }
575
+
576
+ index += 1 ;
577
+
578
+ let length_digits_start = index;
579
+
580
+ while bytes. get ( index) . map_or ( false , u8:: is_ascii_digit) {
581
+ index += 1 ;
582
+ }
583
+
584
+ let length_digits_end = index;
585
+
586
+ if length_digits_start == length_digits_end {
587
+ // No digits found, this also covers the case where we have
588
+ // a normal crate production with disambiguator `Cs<hash><digits><ident>`
589
+ return None ;
590
+ }
591
+
592
+ if length_digits_end >= bytes. len ( ) {
593
+ // We are at the end of the input, this is probably not a well-formed
594
+ // symbol name.
595
+ return None ;
596
+ }
597
+
598
+ if bytes[ length_digits_end] != b'_' {
599
+ // This is another kind of special `C` production, like `C3f16`
600
+ return None ;
601
+ }
602
+
603
+ // Convert the digits to an int
604
+ let mut num_bytes = 0 ;
605
+ for & c in & bytes[ length_digits_start..length_digits_end] {
606
+ num_bytes = num_bytes * 10 + ( c - b'0' ) as usize ;
607
+ }
608
+
609
+ Some ( SkippableSection {
610
+ content_start : length_digits_end + 1 , // +1 to skip the `_` too
611
+ section_end : length_digits_end + num_bytes,
612
+ } )
613
+ }
566
614
}
567
615
568
- struct Printer < ' a , ' b : ' a , ' s > {
616
+ struct Printer < ' a , ' b , ' s > {
569
617
/// The input parser to demangle from, or `Err` if any (parse) error was
570
618
/// encountered (in order to disallow further likely-incorrect demangling).
571
619
///
@@ -661,6 +709,8 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
661
709
return Ok ( ( ) ) ;
662
710
}
663
711
712
+ // TODO: Keep going even if parsing the referenced section failed, so
713
+ // that we can handle backrefs into skippable sections.
664
714
let orig_parser = mem:: replace ( & mut self . parser , Ok ( backref_parser) ) ;
665
715
let r = f ( self ) ;
666
716
self . parser = orig_parser;
@@ -889,14 +939,16 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
889
939
}
890
940
891
941
fn print_generic_arg ( & mut self ) -> fmt:: Result {
892
- if self . eat ( b'L' ) {
893
- let lt = parse ! ( self , integer_62) ;
894
- self . print_lifetime_from_index ( lt)
895
- } else if self . eat ( b'K' ) {
896
- self . print_const ( false )
897
- } else {
898
- self . print_type ( )
899
- }
942
+ self . print_with_fallback ( |this| {
943
+ if this. eat ( b'L' ) {
944
+ let lt = parse ! ( this, integer_62) ;
945
+ this. print_lifetime_from_index ( lt)
946
+ } else if this. eat ( b'K' ) {
947
+ this. print_const ( false )
948
+ } else {
949
+ this. print_type ( )
950
+ }
951
+ } )
900
952
}
901
953
902
954
fn print_type ( & mut self ) -> fmt:: Result {
@@ -1081,7 +1133,6 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
1081
1133
1082
1134
fn print_const ( & mut self , in_value : bool ) -> fmt:: Result {
1083
1135
let tag = parse ! ( self , next) ;
1084
-
1085
1136
parse ! ( self , push_depth) ;
1086
1137
1087
1138
// Only literals (and the names of `const` generic parameters, but they
@@ -1237,12 +1288,76 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
1237
1288
None => invalid ! ( self ) ,
1238
1289
}
1239
1290
}
1291
+
1292
+ fn print_with_fallback ( & mut self , mut f : impl FnMut ( & mut Self ) -> fmt:: Result ) -> fmt:: Result {
1293
+ let skippable_section = self
1294
+ . parser
1295
+ . as_ref ( )
1296
+ . map ( Parser :: peek_skippable_prefix)
1297
+ . unwrap_or_default ( ) ;
1298
+
1299
+ if let Some ( skippable_section) = skippable_section {
1300
+ // If we got here, we know have a valid parser and can unwrap.
1301
+ let self_parser = self . parser . as_mut ( ) . unwrap ( ) ;
1302
+
1303
+ // Create a look-ahead printer to check if we can handle the skippable
1304
+ // section without error.
1305
+ let mut look_ahead = Printer {
1306
+ bound_lifetime_depth : self . bound_lifetime_depth ,
1307
+ out : None , // Don't produce any output
1308
+ parser : Ok ( Parser {
1309
+ depth : self_parser. depth ,
1310
+ sym : & self_parser. sym [ ..skippable_section. section_end ] ,
1311
+ next : skippable_section. content_start ,
1312
+ } ) ,
1313
+ } ;
1314
+
1315
+ // Do the look-ahead parsing. We ignore the result, which is unreliable,
1316
+ // and instead check if the parser still Ok after the parsing
1317
+ let _ = f ( & mut look_ahead) ;
1318
+
1319
+ if look_ahead. parser . is_ok ( ) {
1320
+ // We succeeded, so we eat the skippable section prefix and do the
1321
+ // printing for real.
1322
+ self_parser. next = skippable_section. content_start ;
1323
+ f ( self )
1324
+ } else {
1325
+ // Parsing failed so we emit the contents of the skippable section verbatim.
1326
+ self_parser. next = skippable_section. section_end ;
1327
+ let verbatim = & self_parser. sym
1328
+ [ skippable_section. content_start ..skippable_section. section_end ] ;
1329
+
1330
+ self . print ( "{{{ skipped: " ) ?;
1331
+ self . print ( verbatim) ?;
1332
+ self . print ( " }}}" ) ?;
1333
+ Ok ( ( ) )
1334
+ }
1335
+ } else {
1336
+ f ( self )
1337
+ }
1338
+ }
1339
+ }
1340
+
1341
+ /// A skippable section in a mangled name looks like `C<digits>_<content>`,
1342
+ /// where <digits> is an ASCII decimal designating the number of bytes in
1343
+ /// `<content>` plus one byte for the `_`.
1344
+ /// The `section_end` field is the index in the input array right after the
1345
+ /// end of `<content>`. The `content_start` field is the index at the first
1346
+ /// byte of `<content>`.
1347
+ #[ derive( Debug , PartialEq , Eq ) ]
1348
+ struct SkippableSection {
1349
+ section_end : usize ,
1350
+ content_start : usize ,
1240
1351
}
1241
1352
1242
1353
#[ cfg( test) ]
1243
1354
mod tests {
1244
1355
use std:: prelude:: v1:: * ;
1245
1356
1357
+ use crate :: v0:: SkippableSection ;
1358
+
1359
+ use super :: Parser ;
1360
+
1246
1361
macro_rules! t {
1247
1362
( $a: expr, $b: expr) => { {
1248
1363
assert_eq!( format!( "{}" , :: demangle( $a) ) , $b) ;
@@ -1278,7 +1393,7 @@ mod tests {
1278
1393
1279
1394
#[ test]
1280
1395
fn demangle_crate_with_leading_digit ( ) {
1281
- t_nohash ! ( "_RNvC6_123foo3bar " , "123foo::bar" ) ;
1396
+ t_nohash ! ( "_RNvCs_6_123foo3bar " , "123foo::bar" ) ;
1282
1397
}
1283
1398
1284
1399
#[ test]
@@ -1533,4 +1648,45 @@ mod tests {
1533
1648
1534
1649
assert_contains ! ( :: demangle( & sym) . to_string( ) , "{recursion limit reached}" ) ;
1535
1650
}
1651
+
1652
+ #[ test]
1653
+ fn demangle_const_skippable ( ) {
1654
+ // Parsable
1655
+ t_nohash ! (
1656
+ "_RINtCsHASH_7mycrate3FooxC11_KRe616263_E" ,
1657
+ r#"mycrate::Foo::<i64, "abc">"#
1658
+ ) ;
1659
+
1660
+ // Not Parsable
1661
+ t_nohash ! (
1662
+ "_RINtCsHASH_7mycrate3FooxC8_@$%^&*#E" ,
1663
+ "mycrate::Foo::<i64, {{{ skipped: @$%^&*# }}}>"
1664
+ ) ;
1665
+ }
1666
+
1667
+ #[ test]
1668
+ fn skippable_section_prefix ( ) {
1669
+ macro_rules! test_skippable_prefix {
1670
+ ( $txt: expr, $expected: expr) => { {
1671
+ let p = Parser {
1672
+ depth: 0 ,
1673
+ sym: $txt,
1674
+ next: 0 ,
1675
+ } ;
1676
+ let actual = p. peek_skippable_prefix( ) ;
1677
+ assert_eq!( actual, $expected) ;
1678
+ } } ;
1679
+ }
1680
+
1681
+ test_skippable_prefix ! (
1682
+ "C3_xx" ,
1683
+ Some ( SkippableSection {
1684
+ content_start: 3 ,
1685
+ section_end: 5 ,
1686
+ } )
1687
+ ) ;
1688
+
1689
+ test_skippable_prefix ! ( "Cs1341adsasd_3_xx" , None ) ;
1690
+ test_skippable_prefix ! ( "C3f16" , None ) ;
1691
+ }
1536
1692
}
0 commit comments