Skip to content
Open
150 changes: 147 additions & 3 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1775,7 +1775,7 @@ impl GetTemplateArgs for Name {
Name::UnscopedTemplate(_, ref args) => Some(args),
Name::Nested(ref nested) => nested.get_template_args(subs),
Name::Local(ref local) => local.get_template_args(subs),
Name::Unscoped(_) => None,
Name::Unscoped(ref unscoped) => unscoped.get_template_args(subs),
}
}
}
Expand Down Expand Up @@ -1874,6 +1874,16 @@ impl<'a> GetLeafName<'a> for UnscopedName {
}
}

impl GetTemplateArgs for UnscopedName {
fn get_template_args<'a>(&'a self, subs: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
match *self {
UnscopedName::Unqualified(ref name) | UnscopedName::Std(ref name) => {
name.get_template_args(subs)
}
}
}
}

impl IsCtorDtorConversion for UnscopedName {
fn is_ctor_dtor_conversion(&self, subs: &SubstitutionTable) -> bool {
match *self {
Expand Down Expand Up @@ -2166,7 +2176,11 @@ impl GetTemplateArgs for NestedName {
match *self {
NestedName::Template(_, _, ref prefix)
| NestedName::TemplateExplicitObject(ref prefix, _) => prefix.get_template_args(subs),
_ => None,
// For nested unqualified names, the trailing unqualified component
// (for example local-source-name `L...I...E`) may carry the active
// template arguments.
NestedName::Unqualified(_, _, _, ref name)
| NestedName::UnqualifiedExplicitObject(_, ref name, _) => name.get_template_args(subs),
}
}
}
Expand Down Expand Up @@ -2372,7 +2386,12 @@ impl Parse for PrefixHandle {
current = Some(save(subs, prefix, tail_tail));
tail = consume(b"M", tail_tail).unwrap();
} else {
let prefix = match current {
// Keep substitution ordering stable for local source
// names with template-args that are followed by `M`
// data-member prefixes.
let prev_current = current.take();

let prefix = match prev_current {
None => Prefix::Unqualified(name),
Some(handle) => Prefix::Nested(handle, name),
};
Expand Down Expand Up @@ -2703,6 +2722,13 @@ impl IsCtorDtorConversion for UnqualifiedName {
}
}

impl GetTemplateArgs for UnqualifiedName {
fn get_template_args<'a>(&'a self, _: &'a SubstitutionTable) -> Option<&'a TemplateArgs> {
// Unqualified names do not directly carry template arguments in this AST.
None
}
}

impl UnqualifiedName {
#[inline]
fn starts_with(byte: u8, first: bool, input: &IndexStr) -> bool {
Expand Down Expand Up @@ -8601,6 +8627,7 @@ mod tests {
use crate::error::Error;
use crate::index_str::IndexStr;
use crate::subs::{Substitutable, SubstitutionTable};
use crate::Symbol;
use alloc::boxed::Box;
use alloc::string::String;
use core::fmt::Debug;
Expand Down Expand Up @@ -10156,6 +10183,112 @@ mod tests {
});
}

#[test]
fn parse_realworld_makesharedbufferviewwithouter_full_mangled_name_probe() {
let mut subs = SubstitutionTable::new();
let ctx = ParseContext::new(Default::default());
let input = IndexStr::new(
b"_ZL29MakeSharedBufferViewWithOuterIRK13FSharedBufferTnPDTcvS0_cl7DeclValIT_EEELPS0_0EES0_11TMemoryViewIKvEOS3_",
);

match MangledName::parse(&ctx, &mut subs, input) {
Ok((_name, tail)) => assert!(
tail.is_empty(),
"makesharedbufferviewwithouter full parse left tail: {:?}",
String::from_utf8_lossy(tail.as_ref())
),
Err(err) => panic!(
"failed makesharedbufferviewwithouter full mangled name: {:?}",
err
),
}
}

#[test]
fn demangle_realworld_makesharedbufferviewwithouter_probe() {
let mangled = b"_ZL29MakeSharedBufferViewWithOuterIRK13FSharedBufferTnPDTcvS0_cl7DeclValIT_EEELPS0_0EES0_11TMemoryViewIKvEOS3_";
let sym = Symbol::new(&mangled[..]).expect("symbol parse");
match sym.demangle() {
Ok(_) => {}
Err(err) => panic!("failed makesharedbufferviewwithouter demangle: {:?}", err),
}
}

#[test]
fn parse_realworld_findbounds_full_mangled_name_probe() {
let mut subs = SubstitutionTable::new();
let ctx = ParseContext::new(Default::default());
let input = IndexStr::new(b"_ZL10FindBoundsIfEvRT_S1_S0_S0_fS0_S0_fb");

match MangledName::parse(&ctx, &mut subs, input) {
Ok((_name, tail)) => assert!(
tail.is_empty(),
"findbounds full parse left tail: {:?}",
String::from_utf8_lossy(tail.as_ref())
),
Err(err) => panic!("failed findbounds full mangled name: {:?}", err),
}
}

#[test]
fn demangle_realworld_findbounds_probe() {
let mangled = b"_ZL10FindBoundsIfEvRT_S1_S0_S0_fS0_S0_fb";
let sym = Symbol::new(&mangled[..]).expect("symbol parse");
match sym.demangle() {
Ok(_) => {}
Err(err) => panic!("failed findbounds demangle: {:?}", err),
}
}

#[test]
fn parse_realworld_serialize_uint_delta_full_mangled_name_probe() {
let mut subs = SubstitutionTable::new();
let ctx = ParseContext::new(Default::default());
let input = IndexStr::new(
b"_ZN2UE3Net7PrivateL22SerializeUintDeltaImplIyEEvRNS0_19FNetBitStreamWriterET_S5_PKhjh",
);

match MangledName::parse(&ctx, &mut subs, input) {
Ok((_name, tail)) => assert!(
tail.is_empty(),
"serialize uint delta full parse left tail: {:?}",
String::from_utf8_lossy(tail.as_ref())
),
Err(err) => panic!("failed serialize uint delta full mangled name: {:?}", err),
}
}

#[test]
fn demangle_realworld_serialize_uint_delta_probe() {
let mangled =
b"_ZN2UE3Net7PrivateL22SerializeUintDeltaImplIyEEvRNS0_19FNetBitStreamWriterET_S5_PKhjh";
let sym = Symbol::new(&mangled[..]).expect("symbol parse");
match sym.demangle() {
Ok(_) => {}
Err(err) => panic!("failed serialize uint delta demangle: {:?}", err),
}
}

#[test]
fn demangle_realworld_objparser_parsematerialproperty_probe() {
let mangled = b"_ZN2UE11Interchange14ObjParserUtilsL21ParseMaterialPropertyIiTnMN8FObjData13FMaterialDataET_XadL_ZNS4_17IlluminationModelEEEEEbRS3_11TStringViewIDsE";
let sym = Symbol::new(&mangled[..]).expect("symbol parse");
match sym.demangle() {
Ok(_) => {}
Err(err) => panic!("failed objparser parsematerialproperty demangle: {:?}", err),
}
}

#[test]
fn demangle_realworld_foreachimpl_dispatch_probe() {
let mangled = b"_ZN11ForEachImplL8DispatchI10FPolygonID24FFixAttributesSizeHelperIS1_ELj0EEEv5FNameT0_P26FMeshAttributeArraySetBase";
let sym = Symbol::new(&mangled[..]).expect("symbol parse");
match sym.demangle() {
Ok(_) => {}
Err(err) => panic!("failed foreachimpl dispatch demangle: {:?}", err),
}
}

#[test]
fn parse_template_arg() {
assert_parse!(TemplateArg {
Expand Down Expand Up @@ -12099,6 +12232,17 @@ mod tests {
),
"..."
}
b"L3fooIiE..." => {
UnqualifiedName::LocalSourceName(
SourceName(Identifier {
start: 2,
end: 5
}),
None,
AbiTags::default(),
),
"IiE..."
}
b"L3foo..." => {
UnqualifiedName::LocalSourceName(
SourceName(Identifier {
Expand Down