Skip to main content

bindgen/ir/
function.rs

1//! Intermediate representation for C/C++ functions and methods.
2
3use super::comp::MethodKind;
4use super::context::{BindgenContext, TypeId};
5use super::dot::DotAttributes;
6use super::item::Item;
7use super::traversal::{EdgeKind, Trace, Tracer};
8use super::ty::TypeKind;
9use crate::callbacks::{ItemInfo, ItemKind};
10use crate::clang::{self, ABIKind, Attribute};
11use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
12use ext_php_rs_clang_sys::CXCallingConv;
13
14use quote::TokenStreamExt;
15use std::io;
16use std::str::FromStr;
17
18const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
19
20/// What kind of function are we looking at?
21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22pub(crate) enum FunctionKind {
23    /// A plain, free function.
24    Function,
25    /// A method of some kind.
26    Method(MethodKind),
27}
28
29impl FunctionKind {
30    /// Given a clang cursor, return the kind of function it represents, or
31    /// `None` otherwise.
32    pub(crate) fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
33        // FIXME(emilio): Deduplicate logic with `ir::comp`.
34        Some(match cursor.kind() {
35            ext_php_rs_clang_sys::CXCursor_FunctionDecl => {
36                FunctionKind::Function
37            }
38            ext_php_rs_clang_sys::CXCursor_Constructor => {
39                FunctionKind::Method(MethodKind::Constructor)
40            }
41            ext_php_rs_clang_sys::CXCursor_Destructor => {
42                FunctionKind::Method(if cursor.method_is_virtual() {
43                    MethodKind::VirtualDestructor {
44                        pure_virtual: cursor.method_is_pure_virtual(),
45                    }
46                } else {
47                    MethodKind::Destructor
48                })
49            }
50            ext_php_rs_clang_sys::CXCursor_CXXMethod => {
51                if cursor.method_is_virtual() {
52                    FunctionKind::Method(MethodKind::Virtual {
53                        pure_virtual: cursor.method_is_pure_virtual(),
54                    })
55                } else if cursor.method_is_static() {
56                    FunctionKind::Method(MethodKind::Static)
57                } else {
58                    FunctionKind::Method(MethodKind::Normal)
59                }
60            }
61            _ => return None,
62        })
63    }
64}
65
66/// The style of linkage
67#[derive(Debug, Clone, Copy)]
68pub(crate) enum Linkage {
69    /// Externally visible and can be linked against
70    External,
71    /// Not exposed externally. 'static inline' functions will have this kind of linkage
72    Internal,
73}
74
75/// A function declaration, with a signature, arguments, and argument names.
76///
77/// The argument names vector must be the same length as the ones in the
78/// signature.
79#[derive(Debug)]
80pub(crate) struct Function {
81    /// The name of this function.
82    name: String,
83
84    /// The mangled name, that is, the symbol.
85    mangled_name: Option<String>,
86
87    /// The link name. If specified, overwrite `mangled_name`.
88    link_name: Option<String>,
89
90    /// The ID pointing to the current function signature.
91    signature: TypeId,
92
93    /// The kind of function this is.
94    kind: FunctionKind,
95
96    /// The linkage of the function.
97    linkage: Linkage,
98}
99
100impl Function {
101    /// Construct a new function.
102    pub(crate) fn new(
103        name: String,
104        mangled_name: Option<String>,
105        link_name: Option<String>,
106        signature: TypeId,
107        kind: FunctionKind,
108        linkage: Linkage,
109    ) -> Self {
110        Function {
111            name,
112            mangled_name,
113            link_name,
114            signature,
115            kind,
116            linkage,
117        }
118    }
119
120    /// Get this function's name.
121    pub(crate) fn name(&self) -> &str {
122        &self.name
123    }
124
125    /// Get this function's name.
126    pub(crate) fn mangled_name(&self) -> Option<&str> {
127        self.mangled_name.as_deref()
128    }
129
130    /// Get this function's link name.
131    pub fn link_name(&self) -> Option<&str> {
132        self.link_name.as_deref()
133    }
134
135    /// Get this function's signature type.
136    pub(crate) fn signature(&self) -> TypeId {
137        self.signature
138    }
139
140    /// Get this function's kind.
141    pub(crate) fn kind(&self) -> FunctionKind {
142        self.kind
143    }
144
145    /// Get this function's linkage.
146    pub(crate) fn linkage(&self) -> Linkage {
147        self.linkage
148    }
149}
150
151impl DotAttributes for Function {
152    fn dot_attributes<W>(
153        &self,
154        _ctx: &BindgenContext,
155        out: &mut W,
156    ) -> io::Result<()>
157    where
158        W: io::Write,
159    {
160        if let Some(ref mangled) = self.mangled_name {
161            let mangled: String =
162                mangled.chars().flat_map(|c| c.escape_default()).collect();
163            writeln!(out, "<tr><td>mangled name</td><td>{mangled}</td></tr>")?;
164        }
165
166        Ok(())
167    }
168}
169
170/// A valid rust ABI.
171#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
172pub enum Abi {
173    /// The default C ABI.
174    C,
175    /// The "stdcall" ABI.
176    Stdcall,
177    /// The "efiapi" ABI.
178    EfiApi,
179    /// The "fastcall" ABI.
180    Fastcall,
181    /// The "thiscall" ABI.
182    ThisCall,
183    /// The "vectorcall" ABI.
184    Vectorcall,
185    /// The "aapcs" ABI.
186    Aapcs,
187    /// The "win64" ABI.
188    Win64,
189    /// The "C-unwind" ABI.
190    CUnwind,
191    /// The "system" ABI.
192    System,
193}
194
195impl FromStr for Abi {
196    type Err = String;
197
198    fn from_str(s: &str) -> Result<Self, Self::Err> {
199        match s {
200            "C" => Ok(Self::C),
201            "stdcall" => Ok(Self::Stdcall),
202            "efiapi" => Ok(Self::EfiApi),
203            "fastcall" => Ok(Self::Fastcall),
204            "thiscall" => Ok(Self::ThisCall),
205            "vectorcall" => Ok(Self::Vectorcall),
206            "aapcs" => Ok(Self::Aapcs),
207            "win64" => Ok(Self::Win64),
208            "C-unwind" => Ok(Self::CUnwind),
209            "system" => Ok(Self::System),
210            _ => Err(format!("Invalid or unknown ABI {s:?}")),
211        }
212    }
213}
214
215impl std::fmt::Display for Abi {
216    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217        let s = match *self {
218            Self::C => "C",
219            Self::Stdcall => "stdcall",
220            Self::EfiApi => "efiapi",
221            Self::Fastcall => "fastcall",
222            Self::ThisCall => "thiscall",
223            Self::Vectorcall => "vectorcall",
224            Self::Aapcs => "aapcs",
225            Self::Win64 => "win64",
226            Self::CUnwind => "C-unwind",
227            Abi::System => "system",
228        };
229
230        s.fmt(f)
231    }
232}
233
234impl quote::ToTokens for Abi {
235    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
236        let abi = self.to_string();
237        tokens.append_all(quote! { #abi });
238    }
239}
240
241/// An ABI extracted from a clang cursor.
242#[derive(Debug, Copy, Clone)]
243pub(crate) enum ClangAbi {
244    /// An ABI known by Rust.
245    Known(Abi),
246    /// An unknown or invalid ABI.
247    Unknown(CXCallingConv),
248}
249
250impl ClangAbi {
251    /// Returns whether this Abi is known or not.
252    fn is_unknown(self) -> bool {
253        matches!(self, ClangAbi::Unknown(..))
254    }
255}
256
257impl quote::ToTokens for ClangAbi {
258    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
259        match *self {
260            Self::Known(abi) => abi.to_tokens(tokens),
261            Self::Unknown(cc) => panic!(
262                "Cannot turn unknown calling convention to tokens: {cc:?}"
263            ),
264        }
265    }
266}
267
268/// A function signature.
269#[derive(Debug)]
270pub(crate) struct FunctionSig {
271    /// The name of this function signature.
272    name: String,
273
274    /// The return type of the function.
275    return_type: TypeId,
276
277    /// The type of the arguments, optionally with the name of the argument when
278    /// declared.
279    argument_types: Vec<(Option<String>, TypeId)>,
280
281    /// Whether this function is variadic.
282    is_variadic: bool,
283    is_divergent: bool,
284
285    /// Whether this function's return value must be used.
286    must_use: bool,
287
288    /// The ABI of this function.
289    abi: ClangAbi,
290}
291
292fn get_abi(cc: CXCallingConv) -> ClangAbi {
293    use ext_php_rs_clang_sys::*;
294    match cc {
295        // CXCallingConv_PreserveNone (20) - Added in libclang 19 for PHP 8.5+ on macOS ARM64
296        // Map to C calling convention since Rust doesn't have preserve_none ABI
297        cc if cc as u32 == 20 => ClangAbi::Known(Abi::C),
298
299        CXCallingConv_Default | CXCallingConv_C => ClangAbi::Known(Abi::C),
300        CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall),
301        CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall),
302        CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall),
303        CXCallingConv_X86VectorCall | CXCallingConv_AArch64VectorCall => {
304            ClangAbi::Known(Abi::Vectorcall)
305        }
306        CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs),
307        CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64),
308        other => ClangAbi::Unknown(other),
309    }
310}
311
312/// Get the mangled name for the cursor's referent.
313pub(crate) fn cursor_mangling(
314    ctx: &BindgenContext,
315    cursor: &clang::Cursor,
316) -> Option<String> {
317    if !ctx.options().enable_mangling {
318        return None;
319    }
320
321    // We early return here because libclang may crash in some case
322    // if we pass in a variable inside a partial specialized template.
323    // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462.
324    if cursor.is_in_non_fully_specialized_template() {
325        return None;
326    }
327
328    let is_itanium_abi = ctx.abi_kind() == ABIKind::GenericItanium;
329    let is_destructor =
330        cursor.kind() == ext_php_rs_clang_sys::CXCursor_Destructor;
331    if let Ok(mut manglings) = cursor.cxx_manglings() {
332        while let Some(m) = manglings.pop() {
333            // Only generate the destructor group 1, see below.
334            if is_itanium_abi && is_destructor && !m.ends_with("D1Ev") {
335                continue;
336            }
337
338            return Some(m);
339        }
340    }
341
342    let mut mangling = cursor.mangling();
343    if mangling.is_empty() {
344        return None;
345    }
346
347    if is_itanium_abi && is_destructor {
348        // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
349        // the "destructor group 0" symbol, which means that it'll try to free
350        // memory, which definitely isn't what we want.
351        //
352        // Explicitly force the destructor group 1 symbol.
353        //
354        // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
355        // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
356        // a more friendly explanation.
357        //
358        // We don't need to do this for constructors since clang seems to always
359        // have returned the C1 constructor.
360        //
361        // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
362        // I don't think so, but if it can this would become a linker error
363        // anyway, not an invalid free at runtime.
364        //
365        // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
366        // time.
367        if mangling.ends_with("D0Ev") {
368            let new_len = mangling.len() - 4;
369            mangling.truncate(new_len);
370            mangling.push_str("D1Ev");
371        }
372    }
373
374    Some(mangling)
375}
376
377fn args_from_ty_and_cursor(
378    ty: &clang::Type,
379    cursor: &clang::Cursor,
380    ctx: &mut BindgenContext,
381) -> Vec<(Option<String>, TypeId)> {
382    let cursor_args = cursor.args().unwrap_or_default().into_iter();
383    let type_args = ty.args().unwrap_or_default().into_iter();
384
385    // Argument types can be found in either the cursor or the type, but argument names may only be
386    // found on the cursor. We often have access to both a type and a cursor for each argument, but
387    // in some cases we may only have one.
388    //
389    // Prefer using the type as the source of truth for the argument's type, but fall back to
390    // inspecting the cursor (this happens for Objective C interfaces).
391    //
392    // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor
393    // (this happens for function pointer return types).
394    cursor_args
395        .map(Some)
396        .chain(std::iter::repeat(None))
397        .zip(type_args.map(Some).chain(std::iter::repeat(None)))
398        .take_while(|(cur, ty)| cur.is_some() || ty.is_some())
399        .map(|(arg_cur, arg_ty)| {
400            let name = arg_cur.map(|a| a.spelling()).and_then(|name| {
401                if name.is_empty() {
402                    None
403                } else {
404                    Some(name)
405                }
406            });
407
408            let cursor = arg_cur.unwrap_or(*cursor);
409            let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
410            (name, Item::from_ty_or_ref(ty, cursor, None, ctx))
411        })
412        .collect()
413}
414
415impl FunctionSig {
416    /// Get the function name.
417    pub(crate) fn name(&self) -> &str {
418        &self.name
419    }
420
421    /// Construct a new function signature from the given Clang type.
422    pub(crate) fn from_ty(
423        ty: &clang::Type,
424        cursor: &clang::Cursor,
425        ctx: &mut BindgenContext,
426    ) -> Result<Self, ParseError> {
427        use ext_php_rs_clang_sys::*;
428        debug!("FunctionSig::from_ty {ty:?} {cursor:?}");
429
430        // Skip function templates
431        let kind = cursor.kind();
432        if kind == CXCursor_FunctionTemplate {
433            return Err(ParseError::Continue);
434        }
435
436        let spelling = cursor.spelling();
437
438        // Don't parse operatorxx functions in C++
439        let is_operator = |spelling: &str| {
440            spelling.starts_with("operator")
441                && !clang::is_valid_identifier(spelling)
442        };
443        if is_operator(&spelling) && !ctx.options().represent_cxx_operators {
444            return Err(ParseError::Continue);
445        }
446
447        // Constructors of non-type template parameter classes for some reason
448        // include the template parameter in their name. Just skip them, since
449        // we don't handle well non-type template parameters anyway.
450        if (kind == CXCursor_Constructor || kind == CXCursor_Destructor)
451            && spelling.contains('<')
452        {
453            return Err(ParseError::Continue);
454        }
455
456        let cursor = if cursor.is_valid() {
457            *cursor
458        } else {
459            ty.declaration()
460        };
461
462        let mut args = match kind {
463            CXCursor_FunctionDecl
464            | CXCursor_Constructor
465            | CXCursor_CXXMethod
466            | CXCursor_ObjCInstanceMethodDecl
467            | CXCursor_ObjCClassMethodDecl => {
468                args_from_ty_and_cursor(ty, &cursor, ctx)
469            }
470            _ => {
471                // For non-CXCursor_FunctionDecl, visiting the cursor's children
472                // is the only reliable way to get parameter names.
473                let mut args = vec![];
474                cursor.visit(|c| {
475                    if c.kind() == CXCursor_ParmDecl {
476                        let ty =
477                            Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
478                        let name = c.spelling();
479                        let name =
480                            if name.is_empty() { None } else { Some(name) };
481                        args.push((name, ty));
482                    }
483                    CXChildVisit_Continue
484                });
485
486                if args.is_empty() {
487                    // FIXME(emilio): Sometimes libclang doesn't expose the
488                    // right AST for functions tagged as stdcall and such...
489                    //
490                    // https://bugs.llvm.org/show_bug.cgi?id=45919
491                    args_from_ty_and_cursor(ty, &cursor, ctx)
492                } else {
493                    args
494                }
495            }
496        };
497
498        let (must_use, mut is_divergent) =
499            if ctx.options().enable_function_attribute_detection {
500                let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[
501                    Attribute::MUST_USE,
502                    Attribute::NO_RETURN,
503                    Attribute::NO_RETURN_CPP,
504                ]);
505                (must_use, no_return || no_return_cpp)
506            } else {
507                Default::default()
508            };
509
510        // Check if the type contains __attribute__((noreturn)) outside of parentheses. This is
511        // somewhat fragile, but it seems to be the only way to get at this information as of
512        // libclang 9.
513        let ty_spelling = ty.spelling();
514        let has_attribute_noreturn = ty_spelling
515            .match_indices("__attribute__((noreturn))")
516            .any(|(i, _)| {
517                let depth = ty_spelling[..i]
518                    .bytes()
519                    .filter_map(|ch| match ch {
520                        b'(' => Some(1),
521                        b')' => Some(-1),
522                        _ => None,
523                    })
524                    .sum::<isize>();
525                depth == 0
526            });
527        is_divergent = is_divergent || has_attribute_noreturn;
528
529        let is_method = kind == CXCursor_CXXMethod;
530        let is_constructor = kind == CXCursor_Constructor;
531        let is_destructor = kind == CXCursor_Destructor;
532        if (is_constructor || is_destructor || is_method)
533            && cursor.lexical_parent() != cursor.semantic_parent()
534        {
535            // Only parse constructors once.
536            return Err(ParseError::Continue);
537        }
538
539        if is_method || is_constructor || is_destructor {
540            let is_const = is_method && cursor.method_is_const();
541            let is_virtual = is_method && cursor.method_is_virtual();
542            let is_static = is_method && cursor.method_is_static();
543            if !is_static
544                && (!is_virtual
545                    || ctx.options().use_specific_virtual_function_receiver)
546            {
547                let parent = cursor.semantic_parent();
548                let class = Item::parse(parent, None, ctx)
549                    .expect("Expected to parse the class");
550                // The `class` most likely is not finished parsing yet, so use
551                // the unchecked variant.
552                let class = class.as_type_id_unchecked();
553
554                let class = if is_const {
555                    let const_class_id = ctx.next_item_id();
556                    ctx.build_const_wrapper(
557                        const_class_id,
558                        class,
559                        None,
560                        &parent.cur_type(),
561                    )
562                } else {
563                    class
564                };
565
566                let ptr =
567                    Item::builtin_type(TypeKind::Pointer(class), false, ctx);
568                args.insert(0, (Some("this".into()), ptr));
569            } else if is_virtual {
570                let void = Item::builtin_type(TypeKind::Void, false, ctx);
571                let ptr =
572                    Item::builtin_type(TypeKind::Pointer(void), false, ctx);
573                args.insert(0, (Some("this".into()), ptr));
574            }
575        }
576
577        let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl
578            || kind == CXCursor_ObjCClassMethodDecl
579        {
580            ty.ret_type()
581                .or_else(|| cursor.ret_type())
582                .ok_or(ParseError::Continue)?
583        } else {
584            ty.ret_type().ok_or(ParseError::Continue)?
585        };
586
587        let ret = if is_constructor && ctx.is_target_wasm32() {
588            // Constructors in Clang wasm32 target return a pointer to the object
589            // being constructed.
590            let void = Item::builtin_type(TypeKind::Void, false, ctx);
591            Item::builtin_type(TypeKind::Pointer(void), false, ctx)
592        } else {
593            Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx)
594        };
595
596        // Clang plays with us at "find the calling convention", see #549 and
597        // co. This seems to be a better fix than that commit.
598        let mut call_conv = ty.call_conv();
599        if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() {
600            let cursor_call_conv = ty.call_conv();
601            if cursor_call_conv != CXCallingConv_Invalid {
602                call_conv = cursor_call_conv;
603            }
604        }
605
606        let abi = get_abi(call_conv);
607
608        if abi.is_unknown() {
609            warn!("Unknown calling convention: {call_conv:?}");
610        }
611
612        Ok(Self {
613            name: spelling,
614            return_type: ret,
615            argument_types: args,
616            is_variadic: ty.is_variadic(),
617            is_divergent,
618            must_use,
619            abi,
620        })
621    }
622
623    /// Get this function signature's return type.
624    pub(crate) fn return_type(&self) -> TypeId {
625        self.return_type
626    }
627
628    /// Get this function signature's argument (name, type) pairs.
629    pub(crate) fn argument_types(&self) -> &[(Option<String>, TypeId)] {
630        &self.argument_types
631    }
632
633    /// Get this function signature's ABI.
634    pub(crate) fn abi(
635        &self,
636        ctx: &BindgenContext,
637        name: Option<&str>,
638    ) -> crate::codegen::error::Result<ClangAbi> {
639        // FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx`
640        // instead?.
641        let abi = if let Some(name) = name {
642            if let Some((abi, _)) = ctx
643                .options()
644                .abi_overrides
645                .iter()
646                .find(|(_, regex_set)| regex_set.matches(name))
647            {
648                ClangAbi::Known(*abi)
649            } else {
650                self.abi
651            }
652        } else if let Some((abi, _)) = ctx
653            .options()
654            .abi_overrides
655            .iter()
656            .find(|(_, regex_set)| regex_set.matches(&self.name))
657        {
658            ClangAbi::Known(*abi)
659        } else {
660            self.abi
661        };
662
663        match abi {
664            ClangAbi::Known(Abi::ThisCall)
665                if !ctx.options().rust_features().thiscall_abi =>
666            {
667                Err(crate::codegen::error::Error::UnsupportedAbi("thiscall"))
668            }
669            ClangAbi::Known(Abi::Vectorcall)
670                if !ctx.options().rust_features().vectorcall_abi =>
671            {
672                Err(crate::codegen::error::Error::UnsupportedAbi("vectorcall"))
673            }
674            ClangAbi::Known(Abi::CUnwind)
675                if !ctx.options().rust_features().c_unwind_abi =>
676            {
677                Err(crate::codegen::error::Error::UnsupportedAbi("C-unwind"))
678            }
679            ClangAbi::Known(Abi::EfiApi)
680                if !ctx.options().rust_features().abi_efiapi =>
681            {
682                Err(crate::codegen::error::Error::UnsupportedAbi("efiapi"))
683            }
684            ClangAbi::Known(Abi::Win64) if self.is_variadic() => {
685                Err(crate::codegen::error::Error::UnsupportedAbi("Win64"))
686            }
687            abi => Ok(abi),
688        }
689    }
690
691    /// Is this function signature variadic?
692    pub(crate) fn is_variadic(&self) -> bool {
693        // Clang reports some functions as variadic when they *might* be
694        // variadic. We do the argument check because rust doesn't codegen well
695        // variadic functions without an initial argument.
696        self.is_variadic && !self.argument_types.is_empty()
697    }
698
699    /// Must this function's return value be used?
700    pub(crate) fn must_use(&self) -> bool {
701        self.must_use
702    }
703
704    /// Are function pointers with this signature able to derive Rust traits?
705    /// Rust only supports deriving traits for function pointers with a limited
706    /// number of parameters and a couple ABIs.
707    ///
708    /// For more details, see:
709    ///
710    /// * <https://github.com/rust-lang/rust-bindgen/issues/547>,
711    /// * <https://github.com/rust-lang/rust/issues/38848>,
712    /// * and <https://github.com/rust-lang/rust/issues/40158>
713    pub(crate) fn function_pointers_can_derive(&self) -> bool {
714        if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
715            return false;
716        }
717
718        matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..))
719    }
720
721    /// Whether this function has attributes marking it as divergent.
722    pub(crate) fn is_divergent(&self) -> bool {
723        self.is_divergent
724    }
725}
726
727impl ClangSubItemParser for Function {
728    fn parse(
729        cursor: clang::Cursor,
730        context: &mut BindgenContext,
731    ) -> Result<ParseResult<Self>, ParseError> {
732        use ext_php_rs_clang_sys::*;
733
734        let Some(kind) = FunctionKind::from_cursor(&cursor) else {
735            return Err(ParseError::Continue);
736        };
737
738        debug!("Function::parse({cursor:?}, {:?})", cursor.cur_type());
739        let visibility = cursor.visibility();
740        if visibility != CXVisibility_Default {
741            return Err(ParseError::Continue);
742        }
743        if cursor.access_specifier() == CX_CXXPrivate
744            && !context.options().generate_private_functions
745        {
746            return Err(ParseError::Continue);
747        }
748
749        let linkage = cursor.linkage();
750        let linkage = match linkage {
751            CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
752            CXLinkage_Internal => Linkage::Internal,
753            _ => return Err(ParseError::Continue),
754        };
755
756        if cursor.is_inlined_function()
757            || cursor.definition().is_some_and(|x| x.is_inlined_function())
758        {
759            if !context.options().generate_inline_functions
760                && !context.options().wrap_static_fns
761            {
762                return Err(ParseError::Continue);
763            }
764
765            if cursor.is_deleted_function()
766                && !context.options().generate_deleted_functions
767            {
768                return Err(ParseError::Continue);
769            }
770
771            // We cannot handle `inline` functions that are not `static`.
772            if context.options().wrap_static_fns
773                && cursor.is_inlined_function()
774                && matches!(linkage, Linkage::External)
775            {
776                return Err(ParseError::Continue);
777            }
778        }
779
780        // Grab the signature using Item::from_ty.
781        let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
782
783        let mut name = cursor.spelling();
784        assert!(!name.is_empty(), "Empty function name?");
785
786        if cursor.kind() == CXCursor_Destructor {
787            // Remove the leading `~`. The alternative to this is special-casing
788            // code-generation for destructor functions, which seems less than
789            // ideal.
790            if name.starts_with('~') {
791                name.remove(0);
792            }
793
794            // Add a suffix to avoid colliding with constructors. This would be
795            // technically fine (since we handle duplicated functions/methods),
796            // but seems easy enough to handle it here.
797            name.push_str("_destructor");
798        }
799        if let Some(nm) = context.options().last_callback(|callbacks| {
800            callbacks.generated_name_override(ItemInfo {
801                name: name.as_str(),
802                kind: ItemKind::Function,
803            })
804        }) {
805            name = nm;
806        }
807        assert!(!name.is_empty(), "Empty function name.");
808
809        let mangled_name = cursor_mangling(context, &cursor);
810
811        let link_name = context.options().last_callback(|callbacks| {
812            callbacks.generated_link_name_override(ItemInfo {
813                name: name.as_str(),
814                kind: ItemKind::Function,
815            })
816        });
817
818        let function = Self::new(
819            name.clone(),
820            mangled_name,
821            link_name,
822            sig,
823            kind,
824            linkage,
825        );
826
827        Ok(ParseResult::New(function, Some(cursor)))
828    }
829}
830
831impl Trace for FunctionSig {
832    type Extra = ();
833
834    fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
835    where
836        T: Tracer,
837    {
838        tracer.visit_kind(self.return_type().into(), EdgeKind::FunctionReturn);
839
840        for &(_, ty) in self.argument_types() {
841            tracer.visit_kind(ty.into(), EdgeKind::FunctionParameter);
842        }
843    }
844}