Repository: google/autocxx (rust)

Issue:
Identically named static methods in multiple classes don't work
Thanks to @nside for preparing a test case.

Reproduction:
* Fetch this branch: https://github.com/google/autocxx/compare/main...nside:s2
* `cd demo && RUST_LOG=autocxx_engine=info cargo build -vvv`

Errors include:

```
 cargo:warning=/Users/adriantaylor/Development/autocxx/target/debug/build/autocxx-demo-270e598a22aee01d/out/autocxx-build-dir/cxx/gen1.cxx:4:92: error: use of undeclared identifier 'Empty'
  cargo:warning=std::unique_ptr<R2Rect> Empty_autocxx1_autocxx_wrapper() { return std::make_unique<R2Rect>(Empty()); }
  cargo:warning=                                                                                           ^
  cargo:warning=/Users/adriantaylor/Development/autocxx/target/debug/build/autocxx-demo-270e598a22aee01d/out/autocxx-build-dir/cxx/gen1.cxx:5:124: error: reference to type 'const R2Point' (aka 'const Vector2<double>') could not bind to an lvalue of type 'double'
  cargo:warning=std::unique_ptr<R1Interval> FromPoint_autocxx_wrapper(double arg0) { return std::make_unique<R1Interval>(R2Rect::FromPoint(arg0)); }
  cargo:warning=  
  cargo:warning=/Users/adriantaylor/Development/autocxx/target/debug/build/autocxx-demo-270e598a22aee01d/out/autocxx-build-dir/cxx/gen1.cxx:8:158: error: use of undeclared identifier 'FromPointPair'
  cargo:warning=std::unique_ptr<R2Rect> FromPointPair_autocxx1_autocxx_wrapper(const AutocxxConcrete1& arg0, const AutocxxConcrete1& arg1) { return std::make_unique<R2Rect>(FromPointPair(arg0, arg1)); }
  cargo:warning=                                                                                                                                                             ^
```

Pull request:
Fix multiple static functions with conflicting names
Builds on top of a bindgen fix. Fixes #331.

Patch:
diff --git a/engine/src/conversion/analysis/fun/mod.rs b/engine/src/conversion/analysis/fun/mod.rs
index 955af17b..ba8fba65 100644
--- a/engine/src/conversion/analysis/fun/mod.rs
+++ b/engine/src/conversion/analysis/fun/mod.rs
@@ -639,7 +639,7 @@ impl<'a> FnAnalyzer<'a> {
                             }) => match elem.as_ref() {
                                 Type::Path(typ) => {
                                     let mut this_type = TypeName::from_type_path(typ);
-                                    if this_type.is_cvoid() && pp.ident.to_string() == "this" {
+                                    if this_type.is_cvoid() && pp.ident == "this" {
                                         is_virtual = true;
                                         this_type = virtual_this.ok_or_else(|| {
                                             ConvertError::VirtualThisType(
diff --git a/engine/src/conversion/codegen_rs/fun_codegen.rs b/engine/src/conversion/codegen_rs/fun_codegen.rs
index 420939ae..83c39863 100644
--- a/engine/src/conversion/codegen_rs/fun_codegen.rs
+++ b/engine/src/conversion/codegen_rs/fun_codegen.rs
@@ -192,12 +192,12 @@ fn generate_function_impl(
     rust_name: &str,
     ret_type: &ReturnType,
     unsafety: &Option<Unsafe>,
-) -> Item {
+) -> Box<Item> {
     let (wrapper_params, arg_list) = generate_arg_lists(param_details, false);
     let rust_name = make_ident(&rust_name);
-    Item::Fn(parse_quote! {
+    Box::new(Item::Fn(parse_quote! {
         pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
             cxxbridge::#rust_name ( #(#arg_list),* )
         }
-    })
+    }))
 }
diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs
index da00f93f..f33c5f33 100644
--- a/engine/src/conversion/codegen_rs/mod.rs
+++ b/engine/src/conversion/codegen_rs/mod.rs
@@ -57,7 +57,7 @@ enum Use {
     /// 'use' directive points to bindgen
     UsedFromBindgen,
     /// Some kind of custom item
-    Custom(Item),
+    Custom(Box<Item>),
 }
 
 fn get_string_items() -> Vec<Item> {
@@ -255,7 +255,7 @@ impl<'a> RsCodeGenerator<'a> {
                 ))),
                 Use::UsedFromBindgen => output_items.push(Self::generate_bindgen_use_stmt(ns, id)),
                 Use::Unused => {}
-                Use::Custom(item) => output_items.push(item.clone()),
+                Use::Custom(item) => output_items.push(*item.clone()),
             };
         }
         for (child_name, child_ns_entries) in ns_entries.children() {
diff --git a/engine/src/conversion/parse/parse_foreign_mod.rs b/engine/src/conversion/parse/parse_foreign_mod.rs
index c4ff4810..8d0a65d3 100644
--- a/engine/src/conversion/parse/parse_foreign_mod.rs
+++ b/engine/src/conversion/parse/parse_foreign_mod.rs
@@ -19,7 +19,7 @@ use crate::{
     types::{Namespace, TypeName},
 };
 use std::collections::{HashMap, HashSet};
-use syn::{ForeignItem, Ident, ImplItem, ItemImpl, Type};
+use syn::{Block, Expr, ExprCall, ForeignItem, Ident, ImplItem, ItemImpl, Stmt, Type};
 
 /// Parses a given bindgen-generated 'mod' into suitable
 /// [Api]s. In bindgen output, a given mod concerns
@@ -97,7 +97,10 @@ impl ParseForeignMod {
                 let effective_fun_name = if itm.sig.ident == "new" {
                     ty_id.clone()
                 } else {
-                    itm.sig.ident
+                    match get_called_function(&itm.block) {
+                        Some(id) => id.clone(),
+                        None => itm.sig.ident,
+                    }
                 };
                 self.method_receivers.insert(
                     effective_fun_name,
@@ -123,3 +126,34 @@ impl ParseForeignMod {
         }
     }
 }
+
+/// 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");
+    }
+}
diff --git a/engine/src/known_types.rs b/engine/src/known_types.rs
index 3f068606..67ec1946 100644
--- a/engine/src/known_types.rs
+++ b/engine/src/known_types.rs
@@ -199,9 +199,11 @@ impl TypeDatabase {
     /// which we need to wrap.
     pub(crate) fn is_ctype(&self, ty: &TypeName) -> bool {
         self.get(ty)
-            .map(|td| match td.behavior {
-                Behavior::CVariableLengthByValue | Behavior::CVoid => true,
-                _ => false,
+            .map(|td| {
+                matches!(
+                    td.behavior,
+                    Behavior::CVariableLengthByValue | Behavior::CVoid
+                )
             })
             .unwrap_or(false)
     }
@@ -211,9 +213,11 @@ impl TypeDatabase {
     /// type.
     pub(crate) fn is_cxx_acceptable_generic(&self, ty: &TypeName) -> bool {
         self.get(ty)
-            .map(|x| match x.behavior {
-                Behavior::CxxContainerByValueSafe | Behavior::CxxContainerNotByValueSafe => true,
-                _ => false,
+            .map(|x| {
+                matches!(
+                    x.behavior,
+                    Behavior::CxxContainerByValueSafe | Behavior::CxxContainerNotByValueSafe
+                )
             })
             .unwrap_or(false)
     }
@@ -339,7 +343,7 @@ fn create_type_database() -> TypeDatabase {
         "autocxx::c_void",
         "void",
         Behavior::CVoid,
-        Some(format!("std::os::raw::c_void")),
+        Some("std::os::raw::c_void".into()),
     );
     by_rs_name.insert(TypeName::new_from_user_input(&td.rs_name), td);
 


Test patch:
diff --git a/engine/src/integration_tests.rs b/engine/src/integration_tests.rs
index 762f7cb0..24366231 100644
--- a/engine/src/integration_tests.rs
+++ b/engine/src/integration_tests.rs
@@ -2510,18 +2510,6 @@ fn test_give_nonpod_typedef_by_value() {
 }
 
 #[test]
-#[ignore] // bindgen creates functions called create and create1,
-          // then impl blocks for Bob and Fred which call them from methods each
-          // called simply 'create'. Because of this mismatch we have no way to know
-          // that 'create1' is a static function, and this fails. We _could_ parse
-          // the contents of the impl block methods in order to find out what is
-          // actually being called, but currently bindgen in fact gets this wrong,
-          // and calls 'create' from both of them. The first step to getting this
-          // working would therefore be to make a minimal test case and file it
-          // against bindgen. TODO. Then after that was fixed we could look at
-          // whether it's worth fixing this by parsing the contents of the impl'ed
-          // methods.
-          // https://github.com/google/autocxx/issues/331
 fn test_conflicting_static_functions() {
     let cxx = indoc! {"
         Bob Bob::create() { Bob a; return a; }