Repository: rust-lang/rust-bindgen
Pull request #2228 (2022-06-23 16:55:25)

Generated name override
Addresses issue: https://github.com/rust-lang/rust-bindgen/issues/1375

* Adds `generated_name_override` callback to the `ParseCallbacks` trait.
* Callback is invoked for each function name (after other name-related logic).
* Added test to verify.

This PR is a cleaned up version of previous: https://github.com/rust-lang/rust-bindgen/pull/2214


Patch:
diff --git a/bindgen/callbacks.rs b/bindgen/callbacks.rs
index 9b345449..d0eb4667 100644
--- a/bindgen/callbacks.rs
+++ b/bindgen/callbacks.rs
@@ -31,6 +31,12 @@ pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
         MacroParsingBehavior::Default
     }
 
+    /// This function will run for every function. The returned value determines the name visible
+    /// in the bindings.
+    fn generated_name_override(&self, _function_name: &str) -> Option<String> {
+        None
+    }
+
     /// The integer kind an integer macro should have, given a name and the
     /// value of that macro, or `None` if you want the default to be chosen.
     fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs
index 928b5aad..c160ed81 100644
--- a/bindgen/ir/function.rs
+++ b/bindgen/ir/function.rs
@@ -664,6 +664,12 @@ impl ClangSubItemParser for Function {
             // but seems easy enough to handle it here.
             name.push_str("_destructor");
         }
+        if let Some(callbacks) = context.parse_callbacks() {
+            if let Some(nm) = callbacks.generated_name_override(&name) {
+                name = nm;
+            }
+        }
+        assert!(!name.is_empty(), "Empty function name.");
 
         let mangled_name = cursor_mangling(context, &cursor);
         let comment = cursor.raw_comment();


Test patch:
diff --git a/bindgen-tests/tests/expectations/tests/issue-1375-prefixed-functions.rs b/bindgen-tests/tests/expectations/tests/issue-1375-prefixed-functions.rs
new file mode 100644
index 00000000..835b7579
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/issue-1375-prefixed-functions.rs
@@ -0,0 +1,11 @@
+#![allow(
+    dead_code,
+    non_snake_case,
+    non_camel_case_types,
+    non_upper_case_globals
+)]
+
+extern "C" {
+    #[link_name = "\u{1}my_custom_prefix_function_name"]
+    pub fn function_name(x: ::std::os::raw::c_int);
+}
diff --git a/bindgen-tests/tests/headers/issue-1375-prefixed-functions.h b/bindgen-tests/tests/headers/issue-1375-prefixed-functions.h
new file mode 100644
index 00000000..4264e52d
--- /dev/null
+++ b/bindgen-tests/tests/headers/issue-1375-prefixed-functions.h
@@ -0,0 +1,4 @@
+// bindgen-parse-callbacks: remove-function-prefix-my_custom_prefix_
+
+void my_custom_prefix_function_name(const int x);
+
diff --git a/bindgen-tests/tests/parse_callbacks/mod.rs b/bindgen-tests/tests/parse_callbacks/mod.rs
index b94b54de..6ade71c2 100644
--- a/bindgen-tests/tests/parse_callbacks/mod.rs
+++ b/bindgen-tests/tests/parse_callbacks/mod.rs
@@ -1,5 +1,29 @@
 use bindgen::callbacks::*;
 
+#[derive(Debug)]
+pub struct RemoveFunctionPrefixParseCallback {
+    pub remove_function_prefix: Option<String>,
+}
+
+impl RemoveFunctionPrefixParseCallback {
+    pub fn new(prefix: &str) -> Self {
+        RemoveFunctionPrefixParseCallback {
+            remove_function_prefix: Some(prefix.to_string()),
+        }
+    }
+}
+
+impl ParseCallbacks for RemoveFunctionPrefixParseCallback {
+    fn generated_name_override(&self, function_name: &str) -> Option<String> {
+        if let Some(prefix) = &self.remove_function_prefix {
+            if let Some(name) = function_name.strip_prefix(prefix) {
+                return Some(name.to_string());
+            }
+        }
+        None
+    }
+}
+
 #[derive(Debug)]
 struct EnumVariantRename;
 
@@ -37,6 +61,18 @@ pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
         "blocklisted-type-implements-trait" => {
             Box::new(BlocklistedTypeImplementsTrait)
         }
-        _ => panic!("Couldn't find name ParseCallbacks: {}", cb),
+        call_back => {
+            if call_back.starts_with("remove-function-prefix-") {
+                let prefix = call_back
+                    .split("remove-function-prefix-")
+                    .last()
+                    .to_owned();
+                let lnopc =
+                    RemoveFunctionPrefixParseCallback::new(prefix.unwrap());
+                Box::new(lnopc)
+            } else {
+                panic!("Couldn't find name ParseCallbacks: {}", cb)
+            }
+        }
     }
 }