Skip to content

Commit

Permalink
Report C++ visibility and other details.
Browse files Browse the repository at this point in the history
This change reports extra C++ information about items:

* Whether methods are virtual or pure virtual or neither
* Whether a method is a "special member", e.g. a move constructor
* Whether a method is defaulted or deleted
* C++ visibility (for structs, enums, unions and methods)

It builds on top of rust-lang#3145.

This PR is not yet ready for merge, since we need to merge rust-lang#3139
and then enhance the tests to cover those cases too.

Part of google/autocxx#124
  • Loading branch information
adetaylor committed Feb 21, 2025
1 parent bf438d1 commit 6e90632
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,15 @@

class SomeClass {
public:
SomeClass() = delete;
SomeClass(const SomeClass&) = default;
SomeClass(SomeClass&&);
void named_method();
virtual void virtual_method();
virtual void pure_virtual_method() = 0;
private:
void private_method();
protected:
void protected_method();

};
92 changes: 87 additions & 5 deletions bindgen-tests/tests/parse_callbacks/item_discovery_callback/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use regex::Regex;

use bindgen::callbacks::{
DiscoveredItem, DiscoveredItemId, ParseCallbacks, SourceLocation,
SpecialMemberKind, Visibility,
};
use bindgen::Builder;

Expand Down Expand Up @@ -101,6 +102,7 @@ fn test_item_discovery_callback_c() {
DiscoveredItem::Struct {
original_name: Some("NamedStruct".to_string()),
final_name: "NamedStruct".to_string(),
cpp_visibility: Visibility::Public,
},
4,
8,
Expand All @@ -127,6 +129,7 @@ fn test_item_discovery_callback_c() {
DiscoveredItem::Union {
original_name: Some("NamedUnion".to_string()),
final_name: "NamedUnion".to_string(),
cpp_visibility: Visibility::Public,
},
13,
7,
Expand Down Expand Up @@ -165,6 +168,7 @@ fn test_item_discovery_callback_c() {
ItemExpectations::new(
DiscoveredItem::Enum {
final_name: "NamedEnum".to_string(),
cpp_visibility: Visibility::Public,
},
24,
6,
Expand All @@ -178,6 +182,7 @@ fn test_item_discovery_callback_c() {
DiscoveredItem::Struct {
original_name: None,
final_name: "_bindgen_ty_*".to_string(),
cpp_visibility: Visibility::Public,
},
2,
38,
Expand All @@ -191,6 +196,7 @@ fn test_item_discovery_callback_c() {
DiscoveredItem::Union {
original_name: None,
final_name: "_bindgen_ty_*".to_string(),
cpp_visibility: Visibility::Public,
},
11,
37,
Expand All @@ -216,14 +222,15 @@ fn test_item_discovery_callback_c() {
}

#[test]
fn test_item_discovery_callback_cpp() {
fn test_item_discovery_callback_cpp_features() {
let expected = ExpectationMap::from([
(
DiscoveredItemId::new(1),
ItemExpectations::new(
DiscoveredItem::Struct {
original_name: Some("SomeClass".to_string()),
final_name: "SomeClass".to_string(),
cpp_visibility: Visibility::Public,
},
3,
7,
Expand All @@ -237,16 +244,57 @@ fn test_item_discovery_callback_cpp() {
DiscoveredItem::Method {
final_name: "named_method".to_string(),
parent: DiscoveredItemId::new(1),
cpp_visibility: Visibility::Public,
cpp_special_member: None,
cpp_virtual: None,
cpp_explicit: None,
},
5,
8,
10,
47,
144,
None,
),
),
(
DiscoveredItemId::new(48),
ItemExpectations::new(
DiscoveredItem::Method {
final_name: "protected_method".to_string(),
parent: DiscoveredItemId::new(1),
cpp_visibility: Visibility::Protected,
cpp_special_member: None,
cpp_virtual: None,
cpp_explicit: None,
},
14,
10,
295,
None,
),
),
(
DiscoveredItemId::new(19),
ItemExpectations::new(
DiscoveredItem::Method {
final_name: "new".to_string(),
parent: DiscoveredItemId::new(1),
cpp_visibility: Visibility::Public,
cpp_special_member: Some(
SpecialMemberKind::MoveConstructor,
),
cpp_virtual: None,
cpp_explicit: None,
},
7,
5,
111,
None,
),
),
]);

test_item_discovery_callback(
"/tests/parse_callbacks/item_discovery_callback/header_item_discovery.hpp", expected, identity);
"/tests/parse_callbacks/item_discovery_callback/header_item_discovery.hpp", expected, |b| b.clang_arg("--std=c++11"));
}

/// Returns the expectations corresponding to header_item_discovery_with_namespaces.hpp,
Expand Down Expand Up @@ -361,6 +409,7 @@ fn cpp_expectation_map() -> ExpectationMap {
DiscoveredItem::Struct {
final_name: "L".to_string(),
original_name: Some("L".to_string()),
cpp_visibility: Visibility::Public,
},
25,
12,
Expand All @@ -374,6 +423,7 @@ fn cpp_expectation_map() -> ExpectationMap {
DiscoveredItem::Struct {
final_name: "L_M".to_string(),
original_name: Some("M".to_string()),
cpp_visibility: Visibility::Public,
},
26,
16,
Expand Down Expand Up @@ -597,6 +647,7 @@ pub fn compare_struct_info(
let DiscoveredItem::Struct {
original_name: expected_original_name,
final_name: expected_final_name,
cpp_visibility: expected_cpp_visibility,
} = expected_item
else {
unreachable!()
Expand All @@ -605,6 +656,7 @@ pub fn compare_struct_info(
let DiscoveredItem::Struct {
original_name: generated_original_name,
final_name: generated_final_name,
cpp_visibility: generated_cpp_visibility,
} = generated_item
else {
unreachable!()
Expand All @@ -614,6 +666,10 @@ pub fn compare_struct_info(
return false;
}

if expected_cpp_visibility != generated_cpp_visibility {
return false;
}

match (expected_original_name, generated_original_name) {
(None, None) => true,
(Some(expected_original_name), Some(generated_original_name)) => {
Expand All @@ -630,6 +686,7 @@ pub fn compare_union_info(
let DiscoveredItem::Union {
original_name: expected_original_name,
final_name: expected_final_name,
cpp_visibility: expected_cpp_visibility,
} = expected_item
else {
unreachable!()
Expand All @@ -638,6 +695,7 @@ pub fn compare_union_info(
let DiscoveredItem::Union {
original_name: generated_original_name,
final_name: generated_final_name,
cpp_visibility: generated_cpp_visibility,
} = generated_item
else {
unreachable!()
Expand All @@ -647,6 +705,10 @@ pub fn compare_union_info(
return false;
}

if expected_cpp_visibility != generated_cpp_visibility {
return false;
}

match (expected_original_name, generated_original_name) {
(None, None) => true,
(Some(expected_original_name), Some(generated_original_name)) => {
Expand All @@ -662,13 +724,15 @@ pub fn compare_enum_info(
) -> bool {
let DiscoveredItem::Enum {
final_name: expected_final_name,
cpp_visibility: expected_cpp_visibility,
} = expected_item
else {
unreachable!()
};

let DiscoveredItem::Enum {
final_name: generated_final_name,
cpp_visibility: generated_cpp_visibility,
} = generated_item
else {
unreachable!()
Expand All @@ -677,6 +741,11 @@ pub fn compare_enum_info(
if !compare_names(expected_final_name, generated_final_name) {
return false;
}

if expected_cpp_visibility != generated_cpp_visibility {
return false;
}

true
}

Expand Down Expand Up @@ -755,6 +824,10 @@ pub fn compare_method_info(
let DiscoveredItem::Method {
final_name: expected_final_name,
parent: expected_parent,
cpp_visibility: expected_cpp_visibility,
cpp_special_member: expected_cpp_special_member,
cpp_virtual: expected_cpp_virtual,
cpp_explicit: expected_cpp_explicit,
} = expected_item
else {
unreachable!()
Expand All @@ -763,12 +836,21 @@ pub fn compare_method_info(
let DiscoveredItem::Method {
final_name: generated_final_name,
parent: generated_parent,
cpp_visibility: generated_cpp_visibility,
cpp_special_member: generated_cpp_special_member,
cpp_virtual: generated_cpp_virtual,
cpp_explicit: generated_cpp_explicit,
} = generated_item
else {
unreachable!()
};

if expected_parent != generated_parent {
if expected_parent != generated_parent
|| expected_cpp_explicit != generated_cpp_explicit
|| expected_cpp_special_member != generated_cpp_special_member
|| expected_cpp_virtual != generated_cpp_virtual
|| expected_cpp_visibility != generated_cpp_visibility
{
return false;
}

Expand Down
38 changes: 38 additions & 0 deletions bindgen/callbacks.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
//! A public API for more fine-grained customization of bindgen behavior.
pub use crate::ir::analysis::DeriveTrait;
pub use crate::ir::comp::SpecialMemberKind;
pub use crate::ir::derive::CanDerive as ImplementsTrait;
pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue};
pub use crate::ir::function::Explicitness;
pub use crate::ir::function::Visibility;
pub use crate::ir::int::IntKind;
use std::fmt;

Expand Down Expand Up @@ -208,6 +211,10 @@ pub enum DiscoveredItem {

/// The name of the generated binding
final_name: String,

/// Its C++ visibility. [`Visibility::Public`] unless this is nested
/// in another type.
cpp_visibility: Visibility,
},

/// Represents a union with its original name in C and its generated binding name
Expand All @@ -218,6 +225,10 @@ pub enum DiscoveredItem {

/// The name of the generated binding
final_name: String,

/// Its C++ visibility. [`Visibility::Public`] unless this is nested
/// in another type.
cpp_visibility: Visibility,
},

/// Represents an alias like a typedef
Expand All @@ -239,6 +250,10 @@ pub enum DiscoveredItem {
Enum {
/// The final name of the generated binding
final_name: String,

/// Its C++ visibility. [`Visibility::Public`] unless this is nested
/// in another type.
cpp_visibility: Visibility,
},

/// A module, representing a C++ namespace.
Expand Down Expand Up @@ -269,6 +284,20 @@ pub enum DiscoveredItem {

/// Type to which this method belongs.
parent: DiscoveredItemId,

/// Its C++ visibility.
cpp_visibility: Visibility,

/// Whether this is a C++ "special member".
cpp_special_member: Option<SpecialMemberKind>,

/// Whether this is a C++ virtual function.
cpp_virtual: Option<Virtualness>,

/// Whether this is a C++ function which has been marked
/// `=default` or `=deleted`. Note that deleted functions aren't
/// normally generated without special bindgen options.
cpp_explicit: Option<Explicitness>,
},
}

Expand Down Expand Up @@ -336,6 +365,15 @@ pub struct FieldInfo<'a> {
pub field_type_name: Option<&'a str>,
}

/// Whether a method is virtual or pure virtual.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Virtualness {
/// Not pure virtual.
Virtual,
/// Pure virtual.
PureVirtual,
}

/// Location in the source code. Roughly equivalent to the same type
/// within `clang_sys`.
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
15 changes: 15 additions & 0 deletions bindgen/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,21 @@ impl Cursor {
unsafe { clang_isVirtualBase(self.x) != 0 }
}

// Is this cursor's referent a default constructor?
pub fn is_default_constructor(&self) -> bool {
unsafe { clang_CXXConstructor_isDefaultConstructor(self.x) != 0 }
}

// Is this cursor's referent a copy constructor?
pub fn is_copy_constructor(&self) -> bool {
unsafe { clang_CXXConstructor_isCopyConstructor(self.x) != 0 }
}

// Is this cursor's referent a move constructor?
pub fn is_move_constructor(&self) -> bool {
unsafe { clang_CXXConstructor_isMoveConstructor(self.x) != 0 }
}

/// Try to evaluate this cursor.
pub(crate) fn evaluate(&self) -> Option<EvalResult> {
EvalResult::new(*self)
Expand Down
Loading

0 comments on commit 6e90632

Please sign in to comment.