neo_solidity/ir/build/
selectors.rs

1fn string_literal_bytes(parts: &[PtStringLiteral]) -> Vec<u8> {
2    let mut bytes = Vec::new();
3    for part in parts {
4        bytes.extend_from_slice(part.string.as_bytes());
5    }
6    bytes
7}
8
9fn extract_signature_string(expr: &Expression) -> Option<String> {
10    match expr {
11        Expression::StringLiteral(parts) => {
12            Some(String::from_utf8_lossy(&string_literal_bytes(parts)).to_string())
13        }
14        Expression::FunctionCall(_, func, args) => {
15            if args.len() == 1 {
16                match func.as_ref() {
17                    Expression::Type(_, _) => extract_signature_string(&args[0]),
18                    Expression::Variable(id) if id.name == "bytes" || id.name == "string" => {
19                        extract_signature_string(&args[0])
20                    }
21                    _ => None,
22                }
23            } else {
24                None
25            }
26        }
27        _ => None,
28    }
29}
30
31fn resolve_selector_method_name(expr: &Expression, ctx: &LoweringContext) -> Option<String> {
32    match expr {
33        Expression::Variable(identifier) => {
34            if let Some(state_index) = ctx.state_index_map.get(&identifier.name).copied() {
35                if let Some(meta) = ctx.state_metadata(state_index) {
36                    if meta.is_constant {
37                        if let Some(initializer) = meta.initializer.as_ref() {
38                            return resolve_selector_method_name(initializer, ctx);
39                        }
40                    }
41                }
42            }
43            None
44        }
45        Expression::MemberAccess(_, inner, member) => {
46            if member.name == "selector" {
47                if let Expression::MemberAccess(_, _, function_name) = inner.as_ref() {
48                    if !function_name.name.trim().is_empty() {
49                        return Some(function_name.name.clone());
50                    }
51                }
52            }
53            None
54        }
55        Expression::FunctionCall(_, func, args) => {
56            // Ignore simple casts like bytes4(...) around selector expressions.
57            if matches!(func.as_ref(), Expression::Type(_, _)) && args.len() == 1 {
58                return resolve_selector_method_name(&args[0], ctx);
59            }
60
61            if let Expression::Variable(id) = func.as_ref() {
62                if id.name == "keccak256" && args.len() == 1 {
63                    if let Some(signature) = extract_signature_string(&args[0]) {
64                        let name = signature
65                            .split('(')
66                            .next()
67                            .unwrap_or(signature.as_str())
68                            .trim()
69                            .to_string();
70                        if !name.is_empty() {
71                            return Some(name);
72                        }
73                    }
74                }
75            }
76
77            None
78        }
79        _ => None,
80    }
81}