Support demangling symbols with dot-delimited words at the end
This accounts for values like LLVM IR branch labels.
Closes #15
diff --git a/src/lib.rs b/src/lib.rs
index b1156f4..2d0d7c8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -36,6 +36,7 @@
pub struct Demangle<'a> {
original: &'a str,
inner: &'a str,
+ suffix: &'a str,
valid: bool,
/// The number of ::-separated elements in the original name.
elements: usize,
@@ -98,6 +99,18 @@
}
}
+ // Output like LLVM IR adds extra period-delimited words. See if
+ // we are in that case and save the trailing words if so.
+ let mut suffix = "";
+ if let Some(i) = s.rfind("E.") {
+ let (head, tail) = s.split_at(i + 1); // After the E, before the period
+
+ if is_symbol_like(tail) {
+ s = head;
+ suffix = tail;
+ }
+ }
+
// First validate the symbol. If it doesn't look like anything we're
// expecting, we just print it literally. Note that we must handle non-Rust
// symbols because we could have any function in the backtrace.
@@ -155,6 +168,7 @@
Demangle {
inner: inner,
+ suffix: suffix,
valid: valid,
elements: elements,
original: s,
@@ -202,6 +216,35 @@
s.starts_with('h') && s[1..].chars().all(|c| c.is_digit(16))
}
+fn is_symbol_like(s: &str) -> bool {
+ s.chars().all(|c| {
+ // Once `char::is_ascii_punctuation` and `char::is_ascii_alphanumeric`
+ // have been stable for long enough, use those instead for clarity
+ is_ascii_alphanumeric(c) || is_ascii_punctuation(c)
+ })
+}
+
+// Copied from the documentation of `char::is_ascii_alphanumeric`
+fn is_ascii_alphanumeric(c: char) -> bool {
+ match c {
+ '\u{0041}' ... '\u{005A}' |
+ '\u{0061}' ... '\u{007A}' |
+ '\u{0030}' ... '\u{0039}' => true,
+ _ => false,
+ }
+}
+
+// Copied from the documentation of `char::is_ascii_punctuation`
+fn is_ascii_punctuation(c: char) -> bool {
+ match c {
+ '\u{0021}' ... '\u{002F}' |
+ '\u{003A}' ... '\u{0040}' |
+ '\u{005B}' ... '\u{0060}' |
+ '\u{007B}' ... '\u{007E}' => true,
+ _ => false,
+ }
+}
+
impl<'a> fmt::Display for Demangle<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Alright, let's do this.
@@ -288,6 +331,8 @@
}
}
+ try!(f.write_str(self.suffix));
+
Ok(())
}
}
@@ -399,6 +444,17 @@
}
#[test]
+ fn demangle_llvm_ir_branch_labels() {
+ t!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut::haf9727c2edfbc47b.exit.i.i");
+ t_nohash!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut.exit.i.i");
+ }
+
+ #[test]
+ fn demangle_ignores_suffix_that_doesnt_look_like_a_symbol() {
+ t!("_ZN3fooE.llvm moocow", "_ZN3fooE.llvm moocow");
+ }
+
+ #[test]
fn dont_panic() {
super::demangle("_ZN2222222222222222222222EE").to_string();
super::demangle("_ZN5*70527e27.ll34csaғE").to_string();