summaryrefslogtreecommitdiff
path: root/plugins/workflow_swift/src/demangler/name.rs
blob: fd39d8b7c5602a30e0d0ff842ec53812c3b4a689 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use binaryninja::types::QualifiedName;
use swift_demangler::{ConstructorKind, DestructorKind, HasModule, Symbol};

/// Push a module name into the name parts, skipping `__C` (Swift's internal
/// module for C/Objective-C imports).
fn push_module(parts: &mut Vec<String>, module: Option<&str>) {
    if let Some(m) = module {
        if m != "__C" {
            parts.push(m.to_string());
        }
    }
}

/// Build a qualified name from a symbol's components, omitting parameter types
/// and return type since those are represented directly in the function's type
///
/// Returns `None` for symbol kinds that don't benefit from shortening (e.g.
/// variables, thunks), in which case the caller should fall back to `symbol.display()`.
pub fn build_short_name(symbol: &swift_demangler::Symbol) -> Option<QualifiedName> {
    let mut parts: Vec<String> = Vec::new();

    match symbol {
        Symbol::Function(f) => {
            push_module(&mut parts, f.module());
            if let Some(ct) = f.containing_type() {
                parts.push(ct.to_string());
            }
            parts.push(f.full_name());
        }
        Symbol::Constructor(c) => {
            push_module(&mut parts, c.module());
            if let Some(ct) = c.containing_type() {
                parts.push(ct.to_string());
            }
            let init_name = match c.kind() {
                ConstructorKind::Allocating => "__allocating_init",
                ConstructorKind::Regular => "init",
            };
            let labels: Vec<String> = c
                .labels()
                .iter()
                .map(|l| {
                    l.map(|s| format!("{s}:"))
                        .unwrap_or_else(|| "_:".to_string())
                })
                .collect();
            parts.push(format!("{init_name}({})", labels.join("")));
        }
        Symbol::Destructor(d) => {
            push_module(&mut parts, d.module());
            if let Some(ct) = d.containing_type() {
                parts.push(ct.to_string());
            }
            let deinit_name = match d.kind() {
                DestructorKind::Deallocating => "__deallocating_deinit",
                DestructorKind::IsolatedDeallocating => "__isolated_deallocating_deinit",
                DestructorKind::Regular => "deinit",
            };
            parts.push(deinit_name.to_string());
        }
        // Wrappers: combine the wrapper's display with the inner function's short name.
        Symbol::Attributed(_) | Symbol::Specialization(_) => {
            let inner = match symbol {
                Symbol::Attributed(a) => &*a.inner,
                Symbol::Specialization(s) => &*s.inner,
                _ => unreachable!(),
            };
            return build_short_name(inner).map(|inner_name| {
                QualifiedName::from(format!("{}{}", symbol.display(), inner_name))
            });
        }
        Symbol::Suffixed(s) => {
            return build_short_name(&s.inner)
                .map(|inner_name| QualifiedName::from(format!("{} {}", inner_name, s.suffix)));
        }
        _ => return None,
    }

    if parts.is_empty() {
        return None;
    }

    Some(QualifiedName::from(parts.join(".")))
}