Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions common/code_gen_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,7 @@ fn parse_any(ident: &str) -> syn::Result<Ident> {
/// Formats a C++ (qualified) identifier. Returns an error when `ident` is a C++
/// reserved keyword or is an invalid identifier.
pub fn format_cc_ident(ident: &str) -> Result<Ident> {
ensure!(!ident.is_empty(), "Empty string is not a valid C++ identifier");
ensure!(
!is_cpp_reserved_keyword(ident),
"`{ident}` is a C++ reserved keyword and can't be used as a C++ identifier",
);
check_valid_cc_name(ident)?;
// Explicitly mapping the error via `anyhow!`, because `LexError` is not `Sync`
// (required for `anyhow::Error` to implement `From<LexError>`) and
// therefore we can't just use `?`.
Expand Down Expand Up @@ -378,12 +374,26 @@ impl NamespaceQualifier {

/// Returns `foo::bar::baz::` (reporting errors for C++ keywords).
pub fn format_for_cc(&self) -> Result<TokenStream> {
let namespace_cc_idents = self.cc_idents()?;
Ok(quote! { #(#namespace_cc_idents::)* })
let mut path = quote! {};
for namespace in &self.namespaces {
let namespace = format_cc_ident(namespace)?;
path.extend(quote! { #namespace :: });
}
for (rs_name, cc_name) in &self.nested_records {
let cc_name = format_cc_type_name(&cc_name)?;
path.extend(quote! { #cc_name ::});
}
Ok(path)
}

pub fn cc_idents(&self) -> Result<Vec<Ident>> {
self.parts().map(|ns| format_cc_ident(ns)).collect()
/// Returns `foo::bar::baz::` (never reporting errors).
pub fn format_for_cc_debug(&self) -> String {
let mut path = String::new();
for part in self.parts() {
path.push_str(part);
path.push_str("::");
}
path
}
}

Expand Down
65 changes: 20 additions & 45 deletions rs_bindings_from_cc/generate_bindings/cpp_type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,73 +111,48 @@ pub fn format_cpp_type_inner(
> #ptr
})
}
RsTypeKind::IncompleteRecord { incomplete_record, .. } => {
cpp_type_name_for_item(&Item::IncompleteRecord(Rc::clone(incomplete_record)), ir)
}
RsTypeKind::IncompleteRecord { incomplete_record, .. } => tagless_cpp_type_name_for_item(
&Item::IncompleteRecord(Rc::clone(incomplete_record)),
ir,
),
RsTypeKind::Record { record, .. } => cpp_type_name_for_record(record, ir),
RsTypeKind::Enum { enum_, .. } => cpp_type_name_for_item(&Item::Enum(Rc::clone(enum_)), ir),
RsTypeKind::Enum { enum_, .. } => {
tagless_cpp_type_name_for_item(&Item::Enum(Rc::clone(enum_)), ir)
}
RsTypeKind::TypeAlias { type_alias, .. } => {
cpp_type_name_for_item(&Item::TypeAlias(Rc::clone(type_alias)), ir)
tagless_cpp_type_name_for_item(&Item::TypeAlias(Rc::clone(type_alias)), ir)
}
RsTypeKind::Primitive(primitive) => Ok(quote! { #primitive }),
RsTypeKind::BridgeType { original_type, .. } => cpp_type_name_for_record(original_type, ir),
RsTypeKind::ExistingRustType(existing_rust_type) => {
cpp_type_name_for_item(&Item::ExistingRustType(Rc::clone(existing_rust_type)), ir)
}
RsTypeKind::ExistingRustType(existing_rust_type) => tagless_cpp_type_name_for_item(
&Item::ExistingRustType(Rc::clone(existing_rust_type)),
ir,
),
RsTypeKind::C9Co { original_type, .. } => cpp_type_name_for_record(original_type, ir),
}
}

/// Returns the fully-qualified name for an item, not including the type tag.
pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
if let ir::Item::Record(record) = item {
cpp_tagless_type_name_for_record(record, ir)
} else {
cpp_type_name_for_item(item, ir)
}
}

/// Returns the fully qualified name for an item.
/// Returns the fully qualified name for an item (not including type tags).
///
/// For example, for `namespace x { struct Y { using X = int; }; }`, the name
/// for `X` is `x::Y::X`.
fn cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
/// Returns the namespace / class qualifiers necessary to access the item.
///
/// For example, for `namespace x { struct Y { using X = int; }; }`, the prefix
/// for `X` is `x::Y::`.
fn cpp_qualified_path_prefix(item: &ir::Item, ir: &ir::IR) -> Result<TokenStream> {
let Some(parent) = item.enclosing_item_id() else {
return Ok(quote! {});
};
let parent: &ir::Item = ir.find_decl(parent)?;
match parent {
ir::Item::Namespace(_) => Ok(ir.namespace_qualifier(item).format_for_cc()?),
ir::Item::Record(r) => {
let name = cpp_tagless_type_name_for_record(r, ir)?;
Ok(quote! {#name ::})
}
_ => bail!("Unexpected enclosing item: {item:?}"),
}
}

pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
match item {
Item::IncompleteRecord(incomplete_record) => {
let ident = expect_format_cc_type_name(incomplete_record.cc_name.identifier.as_ref());
let namespace_qualifier = ir.namespace_qualifier(incomplete_record).format_for_cc()?;
let tag_kind = incomplete_record.record_type;
Ok(quote! { #tag_kind #namespace_qualifier #ident })
Ok(quote! { #namespace_qualifier #ident })
}
Item::Record(record) => cpp_type_name_for_record(record, ir),
Item::Record(record) => cpp_tagless_type_name_for_record(record, ir),
Item::Enum(enum_) => {
let ident = expect_format_cc_type_name(&enum_.rs_name.identifier);
let qualifier = cpp_qualified_path_prefix(item, ir)?;
Ok(quote! { #qualifier #ident })
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
Ok(quote! { #namespace_qualifier #ident })
}
Item::TypeAlias(type_alias) => {
let ident = expect_format_cc_type_name(&type_alias.cc_name.identifier);
let qualifier = cpp_qualified_path_prefix(item, ir)?;
Ok(quote! { #qualifier #ident })
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
Ok(quote! { #namespace_qualifier #ident })
}
Item::ExistingRustType(existing_rust_type) => existing_rust_type
.cc_name
Expand Down
73 changes: 25 additions & 48 deletions rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,44 +260,32 @@ fn generate_function_assertation_for_identifier(
let ir = db.ir();

let fn_ident = expect_format_cc_ident(&id.identifier);
let path_to_func = ir.namespace_qualifier(func).format_for_cc()?;
let implementation_function = quote! { :: #path_to_func #fn_ident };
let method_qualification;
let implementation_function;
let member_function_prefix;
let func_params;
if let Some(meta) = func.member_func_metadata.as_ref() {
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
let record_ident = expect_format_cc_type_name(record.cc_name.identifier.as_ref());
let namespace_qualifier = ir.namespace_qualifier(record).format_for_cc()?;
if let Some(instance_method_metadata) = meta.instance_method_metadata.as_ref() {
let const_qualifier = if instance_method_metadata.is_const {
quote! {const}
} else {
quote! {}
};

method_qualification = match instance_method_metadata.reference {
ir::ReferenceQualification::Unqualified => const_qualifier,
ir::ReferenceQualification::LValue => {
quote! { #const_qualifier & }
}
ir::ReferenceQualification::RValue => {
quote! { #const_qualifier && }
}
};
implementation_function = quote! { #namespace_qualifier #record_ident :: #fn_ident };
member_function_prefix = quote! { :: #namespace_qualifier #record_ident :: };
// The first parameter of instance methods is `this`.
func_params = &func.params[1..];
if let Some(instance_method_metadata) = func.instance_method_metadata() {
let const_qualifier = if instance_method_metadata.is_const {
quote! {const}
} else {
method_qualification = quote! {};
implementation_function = quote! { #namespace_qualifier #record_ident :: #fn_ident };
member_function_prefix = quote! {};
func_params = &func.params[..];
}
quote! {}
};

method_qualification = match instance_method_metadata.reference {
ir::ReferenceQualification::Unqualified => const_qualifier,
ir::ReferenceQualification::LValue => {
quote! { #const_qualifier & }
}
ir::ReferenceQualification::RValue => {
quote! { #const_qualifier && }
}
};
member_function_prefix = path_to_func;
// The first parameter of instance methods is `this`.
func_params = &func.params[1..];
} else {
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
method_qualification = quote! {};
implementation_function = quote! { #namespace_qualifier #fn_ident };
member_function_prefix = quote! {};
func_params = &func.params[..];
}
Expand Down Expand Up @@ -394,22 +382,11 @@ pub fn generate_function_thunk_impl(
}
UnqualifiedIdentifier::Identifier(id) => {
let fn_ident = expect_format_cc_ident(&id.identifier);
match func.member_func_metadata.as_ref() {
Some(meta) => {
if meta.instance_method_metadata.is_some() {
quote! { #fn_ident }
} else {
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
let record_name =
expect_format_cc_type_name(record.cc_name.identifier.as_ref());
let namespace_qualifier = ir.namespace_qualifier(record).format_for_cc()?;
quote! { #namespace_qualifier #record_name :: #fn_ident }
}
}
None => {
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
quote! { #namespace_qualifier #fn_ident }
}
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
if func.instance_method_metadata().is_some() {
quote! {#fn_ident}
} else {
quote! { #namespace_qualifier #fn_ident }
}
}
// Use `destroy_at` to avoid needing to spell out the class name. Destructor identiifers
Expand Down
83 changes: 52 additions & 31 deletions rs_bindings_from_cc/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,25 +870,35 @@ impl GenericItem for Func {
Some(self.owning_target.clone())
}
fn debug_name(&self, ir: &IR) -> Rc<str> {
let record: Option<Rc<str>> = ir.record_for_member_func(self).map(|r| r.debug_name(ir));
let record: Option<&str> = record.as_deref();
let mut name = ir.namespace_qualifier(self).format_for_cc_debug();
let record_name = || -> Option<Rc<str>> {
let record = ir.record_for_member_func(self)?;
if let Item::Record(r) = record {
Some(r.cc_name.identifier.clone())
} else {
None
}
};

let func_name = match &self.rs_name {
UnqualifiedIdentifier::Identifier(id) => id.identifier.to_string(),
UnqualifiedIdentifier::Operator(op) => op.cc_name(),
match &self.cc_name {
UnqualifiedIdentifier::Identifier(id) => {
name.push_str(&id.identifier);
}
UnqualifiedIdentifier::Operator(op) => {
name.push_str(&op.cc_name());
}
UnqualifiedIdentifier::Destructor => {
format!("~{}", record.expect("destructor must be associated with a record"))
name.push_str("~");
name.push_str(&record_name().expect("destructor must be associated with a record"));
}
UnqualifiedIdentifier::Constructor => {
record.expect("constructor must be associated with a record").to_string()
name.push_str(
&record_name().expect("constructor must be associated with a record"),
);
}
};

if let Some(record_name) = record {
format!("{}::{}", record_name, func_name).into()
} else {
func_name.into()
}

name.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
if self.cc_name == UnqualifiedIdentifier::Constructor {
Expand All @@ -909,11 +919,16 @@ impl GenericItem for Func {
}

impl Func {
pub fn instance_method_metadata(&self) -> Option<&InstanceMethodMetadata> {
if let Some(meta) = &self.member_func_metadata {
if let Some(instance_method_metadata) = &meta.instance_method_metadata {
return Some(instance_method_metadata);
}
}
None
}
pub fn is_instance_method(&self) -> bool {
self.member_func_metadata
.as_ref()
.filter(|meta| meta.instance_method_metadata.is_some())
.is_some()
self.instance_method_metadata().is_some()
}
}

Expand Down Expand Up @@ -987,8 +1002,9 @@ impl GenericItem for IncompleteRecord {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.cc_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
self.record_type.unsupported_item_kind()
Expand Down Expand Up @@ -1176,8 +1192,9 @@ impl GenericItem for Record {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.cc_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
self.record_type.unsupported_item_kind()
Expand Down Expand Up @@ -1325,8 +1342,9 @@ impl GenericItem for GlobalVar {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::GlobalVar
Expand Down Expand Up @@ -1370,8 +1388,9 @@ impl GenericItem for Enum {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Enum
Expand Down Expand Up @@ -1419,8 +1438,9 @@ impl GenericItem for TypeAlias {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::TypeAlias
Expand Down Expand Up @@ -1640,7 +1660,7 @@ impl GenericItem for Comment {
None
}
fn debug_name(&self, _: &IR) -> Rc<str> {
"comment".into()
"<comment>".into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Other
Expand Down Expand Up @@ -1680,8 +1700,9 @@ impl GenericItem for Namespace {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.to_string().into()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Namespace
Expand Down Expand Up @@ -1714,7 +1735,7 @@ impl GenericItem for UseMod {
None
}
fn debug_name(&self, _: &IR) -> Rc<str> {
format!("[internal] use mod {}::* = {}", self.mod_name, self.path).into()
format!("<[internal] use mod {}::* = {}>", self.mod_name, self.path).into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Other
Expand Down
Loading
Loading