Skip to content

Commit 6e07982

Browse files
committed
Demangle explicitly named object parameters
This is a patch that allows for the ability to demangle code like: ``` struct Foo { void bar(this Foo && self); }; ``` An example mangling is `_ZNH1S3fooES_` which then demangles to `S::foo(this S)`. The proposal can be found here: itanium-cxx-abi/cxx-abi#148
1 parent 15bbde1 commit 6e07982

File tree

2 files changed

+95
-21
lines changed

2 files changed

+95
-21
lines changed

src/ast.rs

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,8 @@ where
556556
// argument pack.
557557
is_template_argument_pack: bool,
558558

559+
is_explicit_obj_param: bool,
560+
559561
// Whether to show function parameters.
560562
// This must be set to true before calling `demangle` on `Encoding`
561563
// unless that call is via the toplevel call to `MangledName::demangle`.
@@ -615,6 +617,7 @@ where
615617
is_template_prefix: false,
616618
is_template_prefix_in_nested_name: false,
617619
is_template_argument_pack: false,
620+
is_explicit_obj_param: false,
618621
show_params: !options.no_params,
619622
show_return_type: !options.no_return_type,
620623
show_expression_literal_types: !options.hide_expression_literal_types,
@@ -1037,6 +1040,12 @@ where
10371040
}
10381041

10391042
let mut need_comma = false;
1043+
1044+
// Only the first param should have `this`.
1045+
if ctx.is_explicit_obj_param {
1046+
write!(ctx, "this ")?;
1047+
}
1048+
10401049
for arg in self.iter() {
10411050
if need_comma {
10421051
write!(ctx, ", ")?;
@@ -1938,19 +1947,23 @@ impl<'a> GetLeafName<'a> for UnscopedTemplateName {
19381947
/// ```text
19391948
/// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
19401949
/// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
1950+
/// ::= N H <prefix> <unqualified-name> E
1951+
/// ::= N H <template-prefix> <template-args> E
1952+
19411953
/// ```
19421954
#[derive(Clone, Debug, PartialEq, Eq)]
19431955
pub enum NestedName {
19441956
/// A nested name.
19451957
Unqualified(
19461958
CvQualifiers,
19471959
Option<RefQualifier>,
1960+
Option<ExplicitObjectParameter>,
19481961
PrefixHandle,
19491962
UnqualifiedName,
19501963
),
19511964

19521965
/// A nested template name. The `<template-args>` are part of the `PrefixHandle`.
1953-
Template(CvQualifiers, Option<RefQualifier>, PrefixHandle),
1966+
Template(CvQualifiers, Option<RefQualifier>, Option<ExplicitObjectParameter>, PrefixHandle),
19541967
}
19551968

19561969
impl Parse for NestedName {
@@ -1963,19 +1976,28 @@ impl Parse for NestedName {
19631976

19641977
let tail = consume(b"N", input)?;
19651978

1966-
let (cv_qualifiers, tail) =
1967-
if let Ok((q, tail)) = try_recurse!(CvQualifiers::parse(ctx, subs, tail)) {
1968-
(q, tail)
1969-
} else {
1970-
(Default::default(), tail)
1971-
};
1979+
let (cv_qualifiers, ref_qualifier, explicit_obj_param, tail) = match tail.peek() {
1980+
Some(b'H') => {
1981+
let (explicit_obj_param, tail) = ExplicitObjectParameter::parse(ctx, subs, tail)?;
1982+
(Default::default(), None, Some(explicit_obj_param), tail)
1983+
}
1984+
_ => {
1985+
let (cv_qualifiers, tail) =
1986+
if let Ok((q, tail)) = try_recurse!(CvQualifiers::parse(ctx, subs, tail)) {
1987+
(q, tail)
1988+
} else {
1989+
(Default::default(), tail)
1990+
};
19721991

1973-
let (ref_qualifier, tail) =
1974-
if let Ok((r, tail)) = try_recurse!(RefQualifier::parse(ctx, subs, tail)) {
1975-
(Some(r), tail)
1976-
} else {
1977-
(None, tail)
1978-
};
1992+
let (ref_qualifier, tail) =
1993+
if let Ok((r, tail)) = try_recurse!(RefQualifier::parse(ctx, subs, tail)) {
1994+
(Some(r), tail)
1995+
} else {
1996+
(None, tail)
1997+
};
1998+
(cv_qualifiers, ref_qualifier, None, tail)
1999+
}
2000+
};
19792001

19802002
let (prefix, tail) = PrefixHandle::parse(ctx, subs, tail)?;
19812003
let tail = consume(b"E", tail)?;
@@ -1988,11 +2010,11 @@ impl Parse for NestedName {
19882010

19892011
match substitutable {
19902012
Some(&Substitutable::Prefix(Prefix::Nested(ref prefix, ref name))) => Ok((
1991-
NestedName::Unqualified(cv_qualifiers, ref_qualifier, prefix.clone(), name.clone()),
2013+
NestedName::Unqualified(cv_qualifiers, ref_qualifier, explicit_obj_param, prefix.clone(), name.clone()),
19922014
tail,
19932015
)),
19942016
Some(&Substitutable::Prefix(Prefix::Template(..))) => Ok((
1995-
NestedName::Template(cv_qualifiers, ref_qualifier, prefix),
2017+
NestedName::Template(cv_qualifiers, ref_qualifier, explicit_obj_param, prefix),
19962018
tail,
19972019
)),
19982020
_ => Err(error::Error::UnexpectedText),
@@ -2017,12 +2039,20 @@ impl NestedName {
20172039
}
20182040
}
20192041

2042+
/// Get the ref-qualifier for this name, if one exists.
2043+
pub fn has_explicit_obj_param(&self) -> bool {
2044+
match *self {
2045+
NestedName::Unqualified(_, _, Some(ref _r), ..)
2046+
| NestedName::Template(_, _, Some(ref _r), ..) => true,
2047+
_ => false,
2048+
}
2049+
}
20202050
// Not public because the prefix means different things for different
20212051
// variants, and for `::Template` it actually contains part of what
20222052
// conceptually belongs to `<nested-name>`.
20232053
fn prefix(&self) -> &PrefixHandle {
20242054
match *self {
2025-
NestedName::Unqualified(_, _, ref p, _) | NestedName::Template(_, _, ref p) => p,
2055+
NestedName::Unqualified(_, _, _, ref p, _) | NestedName::Template(_, _, _, ref p) => p,
20262056
}
20272057
}
20282058
}
@@ -2039,7 +2069,7 @@ where
20392069
let ctx = try_begin_demangle!(self, ctx, scope);
20402070

20412071
match *self {
2042-
NestedName::Unqualified(_, _, ref p, ref name) => {
2072+
NestedName::Unqualified(_, _, _, ref p, ref name) => {
20432073
ctx.push_demangle_node(DemangleNodeType::NestedName);
20442074
p.demangle(ctx, scope)?;
20452075
if name.accepts_double_colon() {
@@ -2048,13 +2078,17 @@ where
20482078
name.demangle(ctx, scope)?;
20492079
ctx.pop_demangle_node();
20502080
}
2051-
NestedName::Template(_, _, ref p) => {
2081+
NestedName::Template(_, _, _, ref p) => {
20522082
ctx.is_template_prefix_in_nested_name = true;
20532083
p.demangle(ctx, scope)?;
20542084
ctx.is_template_prefix_in_nested_name = false;
20552085
}
20562086
}
20572087

2088+
if self.has_explicit_obj_param() {
2089+
ctx.is_explicit_obj_param = true;
2090+
}
2091+
20582092
if let Some(inner) = ctx.pop_inner() {
20592093
inner.demangle_as_inner(ctx, scope)?;
20602094
}
@@ -2075,7 +2109,7 @@ where
20752109
impl GetTemplateArgs for NestedName {
20762110
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
20772111
match *self {
2078-
NestedName::Template(_, _, ref prefix) => prefix.get_template_args(subs),
2112+
NestedName::Template(_, _, _, ref prefix) => prefix.get_template_args(subs),
20792113
_ => None,
20802114
}
20812115
}
@@ -2084,10 +2118,10 @@ impl GetTemplateArgs for NestedName {
20842118
impl<'a> GetLeafName<'a> for NestedName {
20852119
fn get_leaf_name(&'a self, subs: &'a SubstitutionTable) -> Option<LeafName<'a>> {
20862120
match *self {
2087-
NestedName::Unqualified(_, _, ref prefix, ref name) => name
2121+
NestedName::Unqualified(_, _, _,ref prefix, ref name) => name
20882122
.get_leaf_name(subs)
20892123
.or_else(|| prefix.get_leaf_name(subs)),
2090-
NestedName::Template(_, _, ref prefix) => prefix.get_leaf_name(subs),
2124+
NestedName::Template(_, _, _, ref prefix) => prefix.get_leaf_name(subs),
20912125
}
20922126
}
20932127
}
@@ -4018,6 +4052,19 @@ define_vocabulary! {
40184052
}
40194053
}
40204054

4055+
define_vocabulary! {
4056+
/// A <ref-qualifier> production.
4057+
///
4058+
/// ```text
4059+
/// <ref-qualifier> ::= R # & ref-qualifier
4060+
/// ::= O # && ref-qualifier
4061+
/// ```
4062+
#[derive(Clone, Debug, PartialEq, Eq)]
4063+
pub enum ExplicitObjectParameter {
4064+
ExplicitObjectParameter(b"H", "this")
4065+
}
4066+
}
4067+
40214068
define_vocabulary! {
40224069
/// A one of the standard variants of the <builtin-type> production.
40234070
///
@@ -8538,6 +8585,7 @@ mod tests {
85388585
Ok => {
85398586
b"NS0_3abcE..." => {
85408587
Name::Nested(NestedName::Unqualified(CvQualifiers::default(),
8588+
None,
85418589
None,
85428590
PrefixHandle::BackReference(1),
85438591
UnqualifiedName::Source(SourceName(Identifier {
@@ -8660,6 +8708,7 @@ mod tests {
86608708
const_: true,
86618709
},
86628710
Some(RefQualifier::RValueRef),
8711+
None,
86638712
PrefixHandle::BackReference(0),
86648713
UnqualifiedName::Source(
86658714
SourceName(Identifier {
@@ -8677,6 +8726,7 @@ mod tests {
86778726
const_: false,
86788727
},
86798728
Some(RefQualifier::RValueRef),
8729+
None,
86808730
PrefixHandle::BackReference(0),
86818731
UnqualifiedName::Source(
86828732
SourceName(Identifier {
@@ -8694,6 +8744,7 @@ mod tests {
86948744
const_: false,
86958745
},
86968746
None,
8747+
None,
86978748
PrefixHandle::BackReference(0),
86988749
UnqualifiedName::Source(
86998750
SourceName(Identifier {
@@ -8711,6 +8762,7 @@ mod tests {
87118762
const_: true,
87128763
},
87138764
Some(RefQualifier::RValueRef),
8765+
None,
87148766
PrefixHandle::NonSubstitution(NonSubstitution(0))),
87158767
b"...",
87168768
[
@@ -8732,6 +8784,7 @@ mod tests {
87328784
const_: false,
87338785
},
87348786
Some(RefQualifier::RValueRef),
8787+
None,
87358788
PrefixHandle::NonSubstitution(NonSubstitution(0))),
87368789
b"...",
87378790
[
@@ -8753,6 +8806,7 @@ mod tests {
87538806
const_: false,
87548807
},
87558808
None,
8809+
None,
87568810
PrefixHandle::NonSubstitution(NonSubstitution(0))),
87578811
b"...",
87588812
[

tests/tests.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,26 @@ demangles!(
617617
"deluge::gui::menu_item::MasterTranspose::MenuItem(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)"
618618
);
619619

620+
demangles!(
621+
_ZNH1S3fooES_,
622+
"S::foo(this S)"
623+
);
624+
625+
demangles!(
626+
_ZNH1S3barILi5EiEEvS_T0_,
627+
"void S::bar<5, int>(this S, int)"
628+
);
629+
630+
demangles!(
631+
_ZNH1S3bazERKS_,
632+
"S::baz(this S const&)"
633+
);
634+
635+
demangles!(
636+
_ZZNH2ns3Foo3fooES0_iENH4Foo24foo2EOKS1_,
637+
"ns::Foo::foo(this ns::Foo, int)::Foo2::foo2(this Foo2 const&&)"
638+
);
639+
620640
// This symbol previously ran into some mutual recursion and unbounded growth of the substitution table.
621641
// See <https://github.com/gimli-rs/cpp_demangle/issues/277> and <https://github.com/getsentry/symbolic/issues/477>
622642
#[test]

0 commit comments

Comments
 (0)