Discovery callbacks for functions and methods.
This extends the existing discovery callback mechanism to report on functions
and methods. At this stage, we don't say much about them, in order to be
consistent with other discovery callbacks. Subsequent PRs will add
extra callbacks to provide information especially about methods
(virtualness, C++ visibility, etc.) Please request changes if you think
that sort of information should arrive in these callbacks.
Because methods are a fundamentally C++ thing, this splits the
current ParseCallbacks test to cover both a .h and a .hpp header.
Part of https://github.com/google/autocxx/issues/124
diff --git a/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h b/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h
index b2bb04f..eb44e5f 100644
--- a/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h
+++ b/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h
@@ -25,4 +25,8 @@
Fish,
};
-typedef enum NamedEnum AliasOfNamedEnum;
\ No newline at end of file
+typedef enum NamedEnum AliasOfNamedEnum;
+
+// Functions
+
+void named_function();
diff --git a/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.hpp b/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.hpp
new file mode 100644
index 0000000..1de8d99
--- /dev/null
+++ b/bindgen-tests/tests/parse_callbacks/item_discovery_callback/header_item_discovery.hpp
@@ -0,0 +1,6 @@
+// Methods
+
+class SomeClass {
+public:
+ void named_method();
+};
\ No newline at end of file
diff --git a/bindgen-tests/tests/parse_callbacks/item_discovery_callback/mod.rs b/bindgen-tests/tests/parse_callbacks/item_discovery_callback/mod.rs
index 93a2b02..dc16aa2 100644
--- a/bindgen-tests/tests/parse_callbacks/item_discovery_callback/mod.rs
+++ b/bindgen-tests/tests/parse_callbacks/item_discovery_callback/mod.rs
@@ -17,20 +17,26 @@
self.0.borrow_mut().insert(_id, _item);
}
}
-#[test]
-pub fn test_item_discovery_callback() {
+
+fn test_item_discovery_callback(header: &str, expected: HashMap<DiscoveredItemId, DiscoveredItem>) {
let discovery = ItemDiscovery::default();
let info = Rc::clone(&discovery.0);
+ let mut header_path = env!("CARGO_MANIFEST_DIR").to_string();
+ header_path.push_str(header);
+
Builder::default()
- .header(concat!(
- env!("CARGO_MANIFEST_DIR"),
- "/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h"
- ))
+ .header(header_path)
.parse_callbacks(Box::new(discovery))
.generate()
.expect("TODO: panic message");
+
+ compare_item_caches(&info.borrow(), &expected);
+}
+
+#[test]
+fn test_item_discovery_callback_c() {
let expected = ItemCache::from([
(
DiscoveredItemId::new(10),
@@ -87,9 +93,38 @@
final_name: "_bindgen_ty_*".to_string(),
},
),
+ (
+ DiscoveredItemId::new(41),
+ DiscoveredItem::Function {
+ final_name: "named_function".to_string(),
+ },
+ ),
]);
+ test_item_discovery_callback(
+ "/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h", expected);
+}
- compare_item_caches(&info.borrow(), &expected);
+
+#[test]
+fn test_item_discovery_callback_cpp() {
+ let expected = ItemCache::from([
+ (
+ DiscoveredItemId::new(1),
+ DiscoveredItem::Struct {
+ original_name: Some("SomeClass".to_string()),
+ final_name: "SomeClass".to_string(),
+ },
+ ),
+ (
+ DiscoveredItemId::new(2),
+ DiscoveredItem::Method {
+ final_name: "named_method".to_string(),
+ parent: DiscoveredItemId::new(1),
+ },
+ ),
+ ]);
+ test_item_discovery_callback(
+ "/tests/parse_callbacks/item_discovery_callback/header_item_discovery.hpp", expected);
}
pub fn compare_item_caches(generated: &ItemCache, expected: &ItemCache) {
@@ -142,6 +177,12 @@
DiscoveredItem::Enum { .. } => {
compare_enum_info(expected_item, generated_item)
}
+ DiscoveredItem::Function { .. } => {
+ compare_function_info(expected_item, generated_item)
+ }
+ DiscoveredItem::Method { .. } => {
+ compare_method_info(expected_item, generated_item)
+ }
}
}
@@ -279,3 +320,57 @@
compare_item_info(expected_aliased, generated_aliased, expected, generated)
}
+
+pub fn compare_function_info(
+ expected_item: &DiscoveredItem,
+ generated_item: &DiscoveredItem,
+) -> bool {
+ let DiscoveredItem::Function {
+ final_name: expected_final_name,
+ } = expected_item
+ else {
+ unreachable!()
+ };
+
+ let DiscoveredItem::Function {
+ final_name: generated_final_name,
+ } = generated_item
+ else {
+ unreachable!()
+ };
+
+ if !compare_names(expected_final_name, generated_final_name) {
+ return false;
+ }
+ true
+}
+
+pub fn compare_method_info(
+ expected_item: &DiscoveredItem,
+ generated_item: &DiscoveredItem,
+) -> bool {
+ let DiscoveredItem::Method {
+ final_name: expected_final_name,
+ parent: expected_parent,
+ } = expected_item
+ else {
+ unreachable!()
+ };
+
+ let DiscoveredItem::Method {
+ final_name: generated_final_name,
+ parent: generated_parent,
+ } = generated_item
+ else {
+ unreachable!()
+ };
+
+ if expected_parent != generated_parent {
+ return false;
+ }
+
+ if !compare_names(expected_final_name, generated_final_name) {
+ return false;
+ }
+ true
+}
diff --git a/bindgen/callbacks.rs b/bindgen/callbacks.rs
index c2be668..579d708 100644
--- a/bindgen/callbacks.rs
+++ b/bindgen/callbacks.rs
@@ -224,7 +224,22 @@
/// The final name of the generated binding
final_name: String,
},
- // functions, modules, etc.
+
+ /// A function or method.
+ Function {
+ /// The final name used.
+ final_name: String,
+ },
+
+ /// A method.
+ Method {
+ /// The final name used.
+ final_name: String,
+
+ /// Type to which this method belongs.
+ parent: DiscoveredItemId,
+ }
+ // modules, etc.
}
/// Relevant information about a type to which new derive attributes will be added using
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index 8c623ff..24b5ded 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -2481,6 +2481,7 @@
let is_rust_union = is_union && struct_layout.is_rust_union();
+ let discovered_id = DiscoveredItemId::new(item.id().as_usize());
ctx.options().for_each_callback(|cb| {
let discovered_item = match self.kind() {
CompKind::Struct => DiscoveredItem::Struct {
@@ -2502,7 +2503,7 @@
};
cb.new_item_found(
- DiscoveredItemId::new(item.id().as_usize()),
+ discovered_id,
discovered_item,
);
});
@@ -2711,6 +2712,7 @@
&mut method_names,
result,
self,
+ discovered_id,
);
}
}
@@ -2729,6 +2731,7 @@
&mut method_names,
result,
self,
+ discovered_id,
);
}
}
@@ -2742,6 +2745,7 @@
&mut method_names,
result,
self,
+ discovered_id,
);
}
}
@@ -2999,6 +3003,7 @@
method_names: &mut HashSet<String>,
result: &mut CodegenResult<'_>,
_parent: &CompInfo,
+ parent_id: DiscoveredItemId,
) {
assert!({
let cc = &ctx.options().codegen_config;
@@ -3019,6 +3024,7 @@
// First of all, output the actual function.
let function_item = ctx.resolve_item(self.signature());
+ let id = DiscoveredItemId::new(function_item.id().as_usize());
if !function_item.process_before_codegen(ctx, result) {
return;
}
@@ -3065,6 +3071,11 @@
method_names.insert(name.clone());
+ ctx.options().for_each_callback(|cb| cb.new_item_found(id, DiscoveredItem::Method {
+ parent: parent_id,
+ final_name: name.clone(),
+ }));
+
let mut function_name = function_item.canonical_name(ctx);
if times_seen > 0 {
write!(&mut function_name, "{times_seen}").unwrap();
@@ -4540,6 +4551,7 @@
) -> Self::Return {
debug!("<Function as CodeGenerator>::codegen: item = {item:?}");
debug_assert!(item.is_enabled_for_codegen(ctx));
+ let id = DiscoveredItemId::new(item.id().as_usize());
let is_internal = matches!(self.linkage(), Linkage::Internal);
@@ -4656,6 +4668,14 @@
if times_seen > 0 {
write!(&mut canonical_name, "{times_seen}").unwrap();
}
+ ctx.options().for_each_callback(|cb| {
+ cb.new_item_found(
+ id,
+ DiscoveredItem::Function {
+ final_name: canonical_name.to_string(),
+ }
+ );
+ });
let link_name_attr = self.link_name().or_else(|| {
let mangled_name = mangled_name.unwrap_or(name);