Squashed 'third_party/autocxx/' content from commit 629e8fa53

git-subtree-dir: third_party/autocxx
git-subtree-split: 629e8fa531a633164c0b52e2a3cab536d4cd0849
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I62a03b0049f49adf029e0204639cdb5468dde1a1
diff --git a/engine/src/conversion/parse/bindgen_semantic_attributes.rs b/engine/src/conversion/parse/bindgen_semantic_attributes.rs
new file mode 100644
index 0000000..8b789ae
--- /dev/null
+++ b/engine/src/conversion/parse/bindgen_semantic_attributes.rs
@@ -0,0 +1,190 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use proc_macro2::{Ident, TokenStream};
+use syn::{
+    parenthesized,
+    parse::{Parse, Parser},
+    Attribute, LitStr,
+};
+
+use crate::conversion::{
+    api::{CppVisibility, Layout, References, SpecialMemberKind, Virtualness},
+    convert_error::{ConvertErrorWithContext, ErrorContext},
+    ConvertError,
+};
+
+/// The set of all annotations that autocxx_bindgen has added
+/// for our benefit.
+#[derive(Debug)]
+pub(crate) struct BindgenSemanticAttributes(Vec<BindgenSemanticAttribute>);
+
+impl BindgenSemanticAttributes {
+    // Remove `bindgen_` attributes. They don't have a corresponding macro defined anywhere,
+    // so they will cause compilation errors if we leave them in.
+    // We may return an error if one of the bindgen attributes shows that the
+    // item can't be processed.
+    pub(crate) fn new_retaining_others(attrs: &mut Vec<Attribute>) -> Self {
+        let metadata = Self::new(attrs);
+        attrs.retain(|a| a.path.segments.last().unwrap().ident != "cpp_semantics");
+        metadata
+    }
+
+    pub(crate) fn new(attrs: &[Attribute]) -> Self {
+        Self(
+            attrs
+                .iter()
+                .filter_map(|attr| {
+                    if attr.path.segments.last().unwrap().ident == "cpp_semantics" {
+                        let r: Result<BindgenSemanticAttribute, syn::Error> = attr.parse_args();
+                        r.ok()
+                    } else {
+                        None
+                    }
+                })
+                .collect(),
+        )
+    }
+
+    /// Some attributes indicate we can never handle a given item. Check for those.
+    pub(crate) fn check_for_fatal_attrs(
+        &self,
+        id_for_context: &Ident,
+    ) -> Result<(), ConvertErrorWithContext> {
+        if self.has_attr("unused_template_param") {
+            Err(ConvertErrorWithContext(
+                ConvertError::UnusedTemplateParam,
+                Some(ErrorContext::new_for_item(id_for_context.clone())),
+            ))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Whether the given attribute is present.
+    pub(super) fn has_attr(&self, attr_name: &str) -> bool {
+        self.0.iter().any(|a| a.is_ident(attr_name))
+    }
+
+    /// The C++ visibility of the item.
+    pub(super) fn get_cpp_visibility(&self) -> CppVisibility {
+        if self.has_attr("visibility_private") {
+            CppVisibility::Private
+        } else if self.has_attr("visibility_protected") {
+            CppVisibility::Protected
+        } else {
+            CppVisibility::Public
+        }
+    }
+
+    /// Whether the item is virtual.
+    pub(super) fn get_virtualness(&self) -> Virtualness {
+        if self.has_attr("pure_virtual") {
+            Virtualness::PureVirtual
+        } else if self.has_attr("bindgen_virtual") {
+            Virtualness::Virtual
+        } else {
+            Virtualness::None
+        }
+    }
+
+    fn parse_if_present<T: Parse>(&self, annotation: &str) -> Option<T> {
+        self.0
+            .iter()
+            .find(|a| a.is_ident(annotation))
+            .map(|a| a.parse_args().unwrap())
+    }
+
+    fn string_if_present(&self, annotation: &str) -> Option<String> {
+        let ls: Option<LitStr> = self.parse_if_present(annotation);
+        ls.map(|ls| ls.value())
+    }
+
+    /// The in-memory layout of the item.
+    pub(super) fn get_layout(&self) -> Option<Layout> {
+        self.parse_if_present("layout")
+    }
+
+    /// The original C++ name, which bindgen may have changed.
+    pub(super) fn get_original_name(&self) -> Option<String> {
+        self.string_if_present("original_name")
+    }
+
+    /// Whether this is a move constructor or other special member.
+    pub(super) fn special_member_kind(&self) -> Option<SpecialMemberKind> {
+        self.string_if_present("special_member")
+            .map(|kind| match kind.as_str() {
+                "default_ctor" => SpecialMemberKind::DefaultConstructor,
+                "copy_ctor" => SpecialMemberKind::CopyConstructor,
+                "move_ctor" => SpecialMemberKind::MoveConstructor,
+                "dtor" => SpecialMemberKind::Destructor,
+                "assignment_operator" => SpecialMemberKind::AssignmentOperator,
+                _ => panic!("unexpected special_member_kind"),
+            })
+    }
+
+    /// Any reference parameters or return values.
+    pub(super) fn get_reference_parameters_and_return(&self) -> References {
+        let mut results = References::default();
+        for a in &self.0 {
+            if a.is_ident("ret_type_reference") {
+                results.ref_return = true;
+            } else if a.is_ident("ret_type_rvalue_reference") {
+                results.rvalue_ref_return = true;
+            } else if a.is_ident("arg_type_reference") {
+                let r: Result<Ident, syn::Error> = a.parse_args();
+                if let Ok(ls) = r {
+                    results.ref_params.insert(ls);
+                }
+            } else if a.is_ident("arg_type_rvalue_reference") {
+                let r: Result<Ident, syn::Error> = a.parse_args();
+                if let Ok(ls) = r {
+                    results.rvalue_ref_params.insert(ls);
+                }
+            }
+        }
+        results
+    }
+}
+
+#[derive(Debug)]
+struct BindgenSemanticAttribute {
+    annotation_name: Ident,
+    body: Option<TokenStream>,
+}
+
+impl BindgenSemanticAttribute {
+    fn is_ident(&self, name: &str) -> bool {
+        self.annotation_name == name
+    }
+
+    fn parse_args<T: Parse>(&self) -> Result<T, syn::Error> {
+        T::parse.parse2(self.body.as_ref().unwrap().clone())
+    }
+}
+
+impl Parse for BindgenSemanticAttribute {
+    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+        let annotation_name: Ident = input.parse()?;
+        if input.peek(syn::token::Paren) {
+            let body_contents;
+            parenthesized!(body_contents in input);
+            Ok(Self {
+                annotation_name,
+                body: Some(body_contents.parse()?),
+            })
+        } else if !input.is_empty() {
+            Err(input.error("expected nothing"))
+        } else {
+            Ok(Self {
+                annotation_name,
+                body: None,
+            })
+        }
+    }
+}
diff --git a/engine/src/conversion/parse/mod.rs b/engine/src/conversion/parse/mod.rs
new file mode 100644
index 0000000..3f42ce4
--- /dev/null
+++ b/engine/src/conversion/parse/mod.rs
@@ -0,0 +1,14 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod bindgen_semantic_attributes;
+mod parse_bindgen;
+mod parse_foreign_mod;
+
+pub(crate) use bindgen_semantic_attributes::BindgenSemanticAttributes;
+pub(crate) use parse_bindgen::ParseBindgen;
diff --git a/engine/src/conversion/parse/parse_bindgen.rs b/engine/src/conversion/parse/parse_bindgen.rs
new file mode 100644
index 0000000..0818aa5
--- /dev/null
+++ b/engine/src/conversion/parse/parse_bindgen.rs
@@ -0,0 +1,388 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use indexmap::map::IndexMap as HashMap;
+use indexmap::set::IndexSet as HashSet;
+
+use crate::{
+    conversion::{
+        api::{Api, ApiName, NullPhase, StructDetails, SubclassName, TypedefKind, UnanalyzedApi},
+        apivec::ApiVec,
+        ConvertError,
+    },
+    types::Namespace,
+    types::QualifiedName,
+};
+use crate::{
+    conversion::{
+        convert_error::{ConvertErrorWithContext, ErrorContext},
+        error_reporter::report_any_error,
+    },
+    types::validate_ident_ok_for_cxx,
+};
+use autocxx_parser::{IncludeCppConfig, RustPath};
+use syn::{parse_quote, Fields, Ident, Item, Type, TypePath, UseTree};
+
+use super::{
+    super::utilities::generate_utilities, bindgen_semantic_attributes::BindgenSemanticAttributes,
+};
+
+use super::parse_foreign_mod::ParseForeignMod;
+
+/// Parses a bindgen mod in order to understand the APIs within it.
+pub(crate) struct ParseBindgen<'a> {
+    config: &'a IncludeCppConfig,
+    apis: ApiVec<NullPhase>,
+}
+
+fn api_name(ns: &Namespace, id: Ident, attrs: &BindgenSemanticAttributes) -> ApiName {
+    ApiName::new_with_cpp_name(ns, id, attrs.get_original_name())
+}
+
+pub(crate) fn api_name_qualified(
+    ns: &Namespace,
+    id: Ident,
+    attrs: &BindgenSemanticAttributes,
+) -> Result<ApiName, ConvertErrorWithContext> {
+    match validate_ident_ok_for_cxx(&id.to_string()) {
+        Err(e) => {
+            let ctx = ErrorContext::new_for_item(id);
+            Err(ConvertErrorWithContext(e, Some(ctx)))
+        }
+        Ok(..) => Ok(api_name(ns, id, attrs)),
+    }
+}
+
+impl<'a> ParseBindgen<'a> {
+    pub(crate) fn new(config: &'a IncludeCppConfig) -> Self {
+        ParseBindgen {
+            config,
+            apis: ApiVec::new(),
+        }
+    }
+
+    /// Parses items found in the `bindgen` output and returns a set of
+    /// `Api`s together with some other data.
+    pub(crate) fn parse_items(
+        mut self,
+        items: Vec<Item>,
+    ) -> Result<ApiVec<NullPhase>, ConvertError> {
+        let items = Self::find_items_in_root(items)?;
+        if !self.config.exclude_utilities() {
+            generate_utilities(&mut self.apis, self.config);
+        }
+        self.add_apis_from_config();
+        let root_ns = Namespace::new();
+        self.parse_mod_items(items, root_ns);
+        self.confirm_all_generate_directives_obeyed()?;
+        self.replace_extern_cpp_types();
+        Ok(self.apis)
+    }
+
+    /// Some API items are not populated from bindgen output, but instead
+    /// directly from items in the config.
+    fn add_apis_from_config(&mut self) {
+        self.apis
+            .extend(self.config.subclasses.iter().map(|sc| Api::Subclass {
+                name: SubclassName::new(sc.subclass.clone()),
+                superclass: QualifiedName::new_from_cpp_name(&sc.superclass),
+            }));
+        self.apis
+            .extend(self.config.extern_rust_funs.iter().map(|fun| {
+                let id = fun.sig.ident.clone();
+                Api::RustFn {
+                    name: ApiName::new_in_root_namespace(id),
+                    details: fun.clone(),
+                    receiver: fun.receiver.as_ref().map(|receiver_id| {
+                        QualifiedName::new(&Namespace::new(), receiver_id.clone())
+                    }),
+                }
+            }));
+        let unique_rust_types: HashSet<&RustPath> = self.config.rust_types.iter().collect();
+        self.apis.extend(unique_rust_types.into_iter().map(|path| {
+            let id = path.get_final_ident();
+            Api::RustType {
+                name: ApiName::new_in_root_namespace(id.clone()),
+                path: path.clone(),
+            }
+        }));
+        self.apis.extend(
+            self.config
+                .concretes
+                .0
+                .iter()
+                .map(|(cpp_definition, rust_id)| {
+                    let name = ApiName::new_in_root_namespace(rust_id.clone());
+                    Api::ConcreteType {
+                        name,
+                        cpp_definition: cpp_definition.clone(),
+                        rs_definition: None,
+                    }
+                }),
+        );
+    }
+
+    /// We do this last, _after_ we've parsed all the APIs, because we might want to actually
+    /// replace some of the existing APIs (structs/enums/etc.) with replacements.
+    fn replace_extern_cpp_types(&mut self) {
+        let pod_requests: HashSet<_> = self.config.get_pod_requests().iter().collect();
+        let replacements: HashMap<_, _> = self
+            .config
+            .externs
+            .0
+            .iter()
+            .map(|(cpp_definition, details)| {
+                let qn = QualifiedName::new_from_cpp_name(cpp_definition);
+                let pod = pod_requests.contains(&qn.to_cpp_name());
+                (
+                    qn.clone(),
+                    Api::ExternCppType {
+                        name: ApiName::new_from_qualified_name(qn),
+                        details: details.clone(),
+                        pod,
+                    },
+                )
+            })
+            .collect();
+        self.apis
+            .retain(|api| !replacements.contains_key(api.name()));
+        self.apis.extend(replacements.into_iter().map(|(_, v)| v));
+    }
+
+    fn find_items_in_root(items: Vec<Item>) -> Result<Vec<Item>, ConvertError> {
+        for item in items {
+            match item {
+                Item::Mod(root_mod) => {
+                    // With namespaces enabled, bindgen always puts everything
+                    // in a mod called 'root'. We don't want to pass that
+                    // onto cxx, so jump right into it.
+                    assert!(root_mod.ident == "root");
+                    if let Some((_, items)) = root_mod.content {
+                        return Ok(items);
+                    }
+                }
+                _ => return Err(ConvertError::UnexpectedOuterItem),
+            }
+        }
+        Ok(Vec::new())
+    }
+
+    /// Interpret the bindgen-generated .rs for a particular
+    /// mod, which corresponds to a C++ namespace.
+    fn parse_mod_items(&mut self, items: Vec<Item>, ns: Namespace) {
+        // This object maintains some state specific to this namespace, i.e.
+        // this particular mod.
+        let mut mod_converter = ParseForeignMod::new(ns.clone());
+        let mut more_apis = ApiVec::new();
+        for item in items {
+            report_any_error(&ns, &mut more_apis, || {
+                self.parse_item(item, &mut mod_converter, &ns)
+            });
+        }
+        self.apis.append(&mut more_apis);
+        mod_converter.finished(&mut self.apis);
+    }
+
+    fn parse_item(
+        &mut self,
+        item: Item,
+        mod_converter: &mut ParseForeignMod,
+        ns: &Namespace,
+    ) -> Result<(), ConvertErrorWithContext> {
+        match item {
+            Item::ForeignMod(fm) => {
+                mod_converter.convert_foreign_mod_items(fm.items);
+                Ok(())
+            }
+            Item::Struct(s) => {
+                if s.ident.to_string().ends_with("__bindgen_vtable") {
+                    return Ok(());
+                }
+                let annotations = BindgenSemanticAttributes::new(&s.attrs);
+                // cxx::bridge can't cope with type aliases to generic
+                // types at the moment.
+                let name = api_name_qualified(ns, s.ident.clone(), &annotations)?;
+                let err = annotations.check_for_fatal_attrs(&s.ident).err();
+                let api = if ns.is_empty() && self.config.is_rust_type(&s.ident) {
+                    None
+                } else if Self::spot_forward_declaration(&s.fields)
+                    || (Self::spot_zero_length_struct(&s.fields) && err.is_some())
+                {
+                    // Forward declarations are recorded especially because we can't
+                    // store them in UniquePtr or similar.
+                    // Templated forward declarations don't appear with an _unused field (which is what
+                    // we spot in the previous clause) but instead with an _address field.
+                    // So, solely in the case where we're storing up an error about such
+                    // a templated type, we'll also treat such cases as forward declarations.
+                    Some(UnanalyzedApi::ForwardDeclaration { name, err })
+                } else {
+                    let has_rvalue_reference_fields = s.fields.iter().any(|f| {
+                        BindgenSemanticAttributes::new(&f.attrs).has_attr("rvalue_reference")
+                    });
+                    Some(UnanalyzedApi::Struct {
+                        name,
+                        details: Box::new(StructDetails {
+                            vis: annotations.get_cpp_visibility(),
+                            layout: annotations.get_layout(),
+                            item: s,
+                            has_rvalue_reference_fields,
+                        }),
+                        analysis: (),
+                    })
+                };
+                if let Some(api) = api {
+                    if !self.config.is_on_blocklist(&api.name().to_cpp_name()) {
+                        self.apis.push(api);
+                    }
+                }
+                Ok(())
+            }
+            Item::Enum(e) => {
+                let annotations = BindgenSemanticAttributes::new(&e.attrs);
+                let api = UnanalyzedApi::Enum {
+                    name: api_name_qualified(ns, e.ident.clone(), &annotations)?,
+                    item: e,
+                };
+                if !self.config.is_on_blocklist(&api.name().to_cpp_name()) {
+                    self.apis.push(api);
+                }
+                Ok(())
+            }
+            Item::Impl(imp) => {
+                // We *mostly* ignore all impl blocks generated by bindgen.
+                // Methods also appear in 'extern "C"' blocks which
+                // we will convert instead. At that time we'll also construct
+                // synthetic impl blocks.
+                // We do however record which methods were spotted, since
+                // we have no other way of working out which functions are
+                // static methods vs plain functions.
+                mod_converter.convert_impl_items(imp);
+                Ok(())
+            }
+            Item::Mod(itm) => {
+                if let Some((_, items)) = itm.content {
+                    let new_ns = ns.push(itm.ident.to_string());
+                    self.parse_mod_items(items, new_ns);
+                }
+                Ok(())
+            }
+            Item::Use(use_item) => {
+                let mut segs = Vec::new();
+                let mut tree = &use_item.tree;
+                loop {
+                    match tree {
+                        UseTree::Path(up) => {
+                            segs.push(up.ident.clone());
+                            tree = &up.tree;
+                        }
+                        UseTree::Name(un) if un.ident == "root" => break, // we do not add this to any API since we generate equivalent
+                        // use statements in our codegen phase.
+                        UseTree::Rename(urn) => {
+                            let old_id = &urn.ident;
+                            let new_id = &urn.rename;
+                            let new_tyname = QualifiedName::new(ns, new_id.clone());
+                            assert!(segs.remove(0) == "self", "Path didn't start with self");
+                            assert!(
+                                segs.remove(0) == "super",
+                                "Path didn't start with self::super"
+                            );
+                            // This is similar to the path encountered within 'tree'
+                            // but without the self::super prefix which is unhelpful
+                            // in our output mod, because we prefer relative paths
+                            // (we're nested in another mod)
+                            let old_path: TypePath = parse_quote! {
+                                #(#segs)::* :: #old_id
+                            };
+                            let old_tyname = QualifiedName::from_type_path(&old_path);
+                            if new_tyname == old_tyname {
+                                return Err(ConvertErrorWithContext(
+                                    ConvertError::InfinitelyRecursiveTypedef(new_tyname),
+                                    Some(ErrorContext::new_for_item(new_id.clone())),
+                                ));
+                            }
+                            let annotations = BindgenSemanticAttributes::new(&use_item.attrs);
+                            self.apis.push(UnanalyzedApi::Typedef {
+                                name: api_name(ns, new_id.clone(), &annotations),
+                                item: TypedefKind::Use(
+                                    parse_quote! {
+                                        pub use #old_path as #new_id;
+                                    },
+                                    Box::new(Type::Path(old_path)),
+                                ),
+                                old_tyname: Some(old_tyname),
+                                analysis: (),
+                            });
+                            break;
+                        }
+                        _ => {
+                            return Err(ConvertErrorWithContext(
+                                ConvertError::UnexpectedUseStatement(
+                                    segs.into_iter().last().map(|i| i.to_string()),
+                                ),
+                                None,
+                            ))
+                        }
+                    }
+                }
+                Ok(())
+            }
+            Item::Const(const_item) => {
+                let annotations = BindgenSemanticAttributes::new(&const_item.attrs);
+                self.apis.push(UnanalyzedApi::Const {
+                    name: api_name(ns, const_item.ident.clone(), &annotations),
+                    const_item,
+                });
+                Ok(())
+            }
+            Item::Type(ity) => {
+                let annotations = BindgenSemanticAttributes::new(&ity.attrs);
+                // It's known that sometimes bindgen will give us duplicate typedefs with the
+                // same name - see test_issue_264.
+                self.apis.push(UnanalyzedApi::Typedef {
+                    name: api_name(ns, ity.ident.clone(), &annotations),
+                    item: TypedefKind::Type(ity),
+                    old_tyname: None,
+                    analysis: (),
+                });
+                Ok(())
+            }
+            _ => Err(ConvertErrorWithContext(
+                ConvertError::UnexpectedItemInMod,
+                None,
+            )),
+        }
+    }
+
+    fn spot_forward_declaration(s: &Fields) -> bool {
+        Self::spot_field(s, "_unused")
+    }
+
+    fn spot_zero_length_struct(s: &Fields) -> bool {
+        Self::spot_field(s, "_address")
+    }
+
+    fn spot_field(s: &Fields, desired_id: &str) -> bool {
+        s.iter()
+            .filter_map(|f| f.ident.as_ref())
+            .any(|id| id == desired_id)
+    }
+
+    fn confirm_all_generate_directives_obeyed(&self) -> Result<(), ConvertError> {
+        let api_names: HashSet<_> = self
+            .apis
+            .iter()
+            .map(|api| api.name().to_cpp_name())
+            .collect();
+        for generate_directive in self.config.must_generate_list() {
+            if !api_names.contains(&generate_directive) {
+                return Err(ConvertError::DidNotGenerateAnything(generate_directive));
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/engine/src/conversion/parse/parse_foreign_mod.rs b/engine/src/conversion/parse/parse_foreign_mod.rs
new file mode 100644
index 0000000..08c1fd8
--- /dev/null
+++ b/engine/src/conversion/parse/parse_foreign_mod.rs
@@ -0,0 +1,177 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::conversion::api::{ApiName, NullPhase, Provenance};
+use crate::conversion::apivec::ApiVec;
+use crate::conversion::doc_attr::get_doc_attrs;
+use crate::conversion::error_reporter::report_any_error;
+use crate::conversion::{
+    api::{FuncToConvert, UnanalyzedApi},
+    convert_error::ConvertErrorWithContext,
+    convert_error::ErrorContext,
+};
+use crate::{
+    conversion::ConvertError,
+    types::{Namespace, QualifiedName},
+};
+use std::collections::HashMap;
+use syn::{Block, Expr, ExprCall, ForeignItem, Ident, ImplItem, ItemImpl, Stmt, Type};
+
+use super::bindgen_semantic_attributes::BindgenSemanticAttributes;
+
+/// Parses a given bindgen-generated 'mod' into suitable
+/// [Api]s. In bindgen output, a given mod concerns
+/// a specific C++ namespace.
+pub(crate) struct ParseForeignMod {
+    ns: Namespace,
+    // We mostly act upon the functions we see within the 'extern "C"'
+    // block of bindgen output, but we can't actually do this until
+    // we've seen the (possibly subsequent) 'impl' blocks so we can
+    // deduce which functions are actually static methods. Hence
+    // store them.
+    funcs_to_convert: Vec<FuncToConvert>,
+    // Evidence from 'impl' blocks about which of these items
+    // may actually be methods (static or otherwise). Mapping from
+    // function name to type name.
+    method_receivers: HashMap<Ident, QualifiedName>,
+    ignored_apis: ApiVec<NullPhase>,
+}
+
+impl ParseForeignMod {
+    pub(crate) fn new(ns: Namespace) -> Self {
+        Self {
+            ns,
+            funcs_to_convert: Vec::new(),
+            method_receivers: HashMap::new(),
+            ignored_apis: ApiVec::new(),
+        }
+    }
+
+    /// Record information from foreign mod items encountered
+    /// in bindgen output.
+    pub(crate) fn convert_foreign_mod_items(&mut self, foreign_mod_items: Vec<ForeignItem>) {
+        let mut extra_apis = ApiVec::new();
+        for i in foreign_mod_items {
+            report_any_error(&self.ns.clone(), &mut extra_apis, || {
+                self.parse_foreign_item(i)
+            });
+        }
+        self.ignored_apis.append(&mut extra_apis);
+    }
+
+    fn parse_foreign_item(&mut self, i: ForeignItem) -> Result<(), ConvertErrorWithContext> {
+        match i {
+            ForeignItem::Fn(item) => {
+                let annotations = BindgenSemanticAttributes::new(&item.attrs);
+                let doc_attrs = get_doc_attrs(&item.attrs);
+                self.funcs_to_convert.push(FuncToConvert {
+                    provenance: Provenance::Bindgen,
+                    self_ty: None,
+                    ident: item.sig.ident,
+                    doc_attrs,
+                    inputs: item.sig.inputs,
+                    output: item.sig.output,
+                    vis: item.vis,
+                    virtualness: annotations.get_virtualness(),
+                    cpp_vis: annotations.get_cpp_visibility(),
+                    special_member: annotations.special_member_kind(),
+                    unused_template_param: annotations
+                        .has_attr("incomprehensible_param_in_arg_or_return"),
+                    references: annotations.get_reference_parameters_and_return(),
+                    original_name: annotations.get_original_name(),
+                    synthesized_this_type: None,
+                    add_to_trait: None,
+                    is_deleted: annotations.has_attr("deleted"),
+                    synthetic_cpp: None,
+                    variadic: item.sig.variadic.is_some(),
+                });
+                Ok(())
+            }
+            ForeignItem::Static(item) => Err(ConvertErrorWithContext(
+                ConvertError::StaticData(item.ident.to_string()),
+                Some(ErrorContext::new_for_item(item.ident)),
+            )),
+            _ => Err(ConvertErrorWithContext(
+                ConvertError::UnexpectedForeignItem,
+                None,
+            )),
+        }
+    }
+
+    /// Record information from impl blocks encountered in bindgen
+    /// output.
+    pub(crate) fn convert_impl_items(&mut self, imp: ItemImpl) {
+        let ty_id = match *imp.self_ty {
+            Type::Path(typ) => typ.path.segments.last().unwrap().ident.clone(),
+            _ => return,
+        };
+        for i in imp.items {
+            if let ImplItem::Method(itm) = i {
+                let effective_fun_name = match get_called_function(&itm.block) {
+                    Some(id) => id.clone(),
+                    None => itm.sig.ident,
+                };
+                self.method_receivers.insert(
+                    effective_fun_name,
+                    QualifiedName::new(&self.ns, ty_id.clone()),
+                );
+            }
+        }
+    }
+
+    /// Indicate that all foreign mods and all impl blocks have been
+    /// fed into us, and we should process that information to generate
+    /// the resulting APIs.
+    pub(crate) fn finished(mut self, apis: &mut ApiVec<NullPhase>) {
+        apis.append(&mut self.ignored_apis);
+        while !self.funcs_to_convert.is_empty() {
+            let mut fun = self.funcs_to_convert.remove(0);
+            fun.self_ty = self.method_receivers.get(&fun.ident).cloned();
+            apis.push(UnanalyzedApi::Function {
+                name: ApiName::new_with_cpp_name(
+                    &self.ns,
+                    fun.ident.clone(),
+                    fun.original_name.clone(),
+                ),
+                fun: Box::new(fun),
+                analysis: (),
+            })
+        }
+    }
+}
+
+/// bindgen sometimes generates an impl fn called a which calls
+/// a function called a1(), if it's dealing with conflicting names.
+/// We actually care about the name a1, so we have to parse the
+/// name of the actual function call inside the block's body.
+fn get_called_function(block: &Block) -> Option<&Ident> {
+    match block.stmts.first() {
+        Some(Stmt::Expr(Expr::Call(ExprCall { func, .. }))) => match **func {
+            Expr::Path(ref exp) => exp.path.segments.first().map(|ps| &ps.ident),
+            _ => None,
+        },
+        _ => None,
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::get_called_function;
+    use syn::parse_quote;
+    use syn::Block;
+
+    #[test]
+    fn test_get_called_function() {
+        let b: Block = parse_quote! {
+            {
+                call_foo()
+            }
+        };
+        assert_eq!(get_called_function(&b).unwrap().to_string(), "call_foo");
+    }
+}