Skip to content

Commit 9bc8a5d

Browse files
zrlkcopybara-github
authored andcommitted
Move defining_target and debug_name from ir.rs to db.rs
(as well as some strongly associated error-handling functions). This is a prerequisite for moving `find_untyped_decl`, `item_for_type`, `find_decl`, `namespace_qualifier` and `namespace_qualifier_from_id` from `IR` to `BindingsGenerator` (and then to eventually make `IR` completely redundant). PiperOrigin-RevId: 883440900
1 parent 0f240b1 commit 9bc8a5d

File tree

11 files changed

+350
-319
lines changed

11 files changed

+350
-319
lines changed

rs_bindings_from_cc/generate_bindings/database/code_snippet.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,17 @@ pub fn required_crubit_features(
155155
// We refuse to generate bindings if either the definition of an item, or
156156
// instantiation (if it is a template) of an item are in a translation unit
157157
// which doesn't have the required Crubit features.
158-
for target in item.defining_target(ir).into_iter().chain(item.owning_target().as_ref())
158+
for target in db
159+
.defining_target(item.id())
160+
.as_ref()
161+
.into_iter()
162+
.chain(item.owning_target().as_ref())
159163
{
160164
let enabled_features = ir.target_crubit_features(target);
161165
if (alternative_required_features & enabled_features).is_empty() {
162166
missing_features.push(RequiredCrubitFeature {
163167
target: target.clone(),
164-
item: item.debug_name(ir),
168+
item: db.debug_name(item.id()),
165169
missing_features: alternative_required_features,
166170
capability_description: capability_description(),
167171
});
@@ -172,7 +176,9 @@ pub fn required_crubit_features(
172176
let require_rs_type_kind = |missing_features: &mut Vec<RequiredCrubitFeature>,
173177
rs_type_kind: &RsTypeKind,
174178
context: &dyn Fn() -> Rc<str>| {
175-
for target in item.defining_target(ir).into_iter().chain(item.owning_target().as_ref()) {
179+
for target in
180+
db.defining_target(item.id()).as_ref().into_iter().chain(item.owning_target().as_ref())
181+
{
176182
let (missing, desc) =
177183
rs_type_kind.required_crubit_features(ir.target_crubit_features(target));
178184
if !missing.is_empty() {
@@ -186,7 +192,7 @@ pub fn required_crubit_features(
186192
};
187193
missing_features.push(RequiredCrubitFeature {
188194
target: target.clone(),
189-
item: item.debug_name(ir),
195+
item: db.debug_name(item.id()),
190196
missing_features: missing,
191197
capability_description,
192198
});

rs_bindings_from_cc/generate_bindings/database/db.rs

Lines changed: 253 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use crate::code_snippet::{
77
};
88
use crate::function_types::{FunctionId, GeneratedFunction, ImplKind};
99
use crate::rs_snippet::{LifetimeOptions, RsTypeKind, Safety};
10-
use arc_anyhow::{anyhow, Result};
10+
use arc_anyhow::{anyhow, Error, Result};
1111
use crubit_abi_type::CrubitAbiType;
1212
use error_report::{ErrorReporting, ReportFatalError};
1313
use ffi_types::Environment;
14-
use ir::{BazelLabel, CcType, Enum, Field, Func, Record, UnqualifiedIdentifier, IR};
14+
use ir::{BazelLabel, CcType, Enum, Field, Func, GenericItem, Record, UnqualifiedIdentifier, IR};
1515
use proc_macro2::Ident;
1616
use std::collections::HashMap;
1717
use std::rc::Rc;
@@ -163,73 +163,271 @@ memoized::query_group! {
163163
///
164164
/// Implementation: rs_bindings_from_cc/generate_bindings/has_bindings.rs?q=function:resolve_type_names
165165
fn resolve_type_names(&self, parent: Rc<Record>) -> Result<Rc<HashMap<Rc<str>, ResolvedTypeName>>>;
166+
}
167+
}
166168

167-
#[provided]
168-
/// Returns the generated bindings for the given enum.
169-
///
170-
/// Implementation: rs_bindings_from_cc/generate_bindings/generate_enum.rs?q=function:generate_enum
171-
fn generate_enum(&self, enum_: Rc<Enum>) -> Result<ApiSnippets> {
172-
(self.codegen_functions().generate_enum)(self, enum_)
173-
}
169+
impl BindingsGenerator<'_> {
170+
/// Returns the generated bindings for the given enum.
171+
///
172+
/// Implementation: rs_bindings_from_cc/generate_bindings/generate_enum.rs?q=function:generate_enum
173+
pub fn generate_enum(&self, enum_: Rc<Enum>) -> Result<ApiSnippets> {
174+
(self.codegen_functions().generate_enum)(self, enum_)
175+
}
174176

175-
#[provided]
176-
/// Returns the generated bindings for an item, or `Err` if bindings generation
177-
/// failed in such a way as to make the generated bindings as a whole invalid.
178-
///
179-
/// Implementation: rs_bindings_from_cc/generate_bindings/lib.rs?q=function:generate_item
180-
fn generate_item(&self, item: ir::Item) -> Result<ApiSnippets> {
181-
(self.codegen_functions().generate_item)(self, item)
182-
}
177+
/// Returns the generated bindings for an item, or `Err` if bindings generation
178+
/// failed in such a way as to make the generated bindings as a whole invalid.
179+
///
180+
/// Implementation: rs_bindings_from_cc/generate_bindings/lib.rs?q=function:generate_item
181+
pub fn generate_item(&self, item: ir::Item) -> Result<ApiSnippets> {
182+
(self.codegen_functions().generate_item)(self, item)
183+
}
183184

184-
#[provided]
185-
/// Returns the generated bindings for the given record, along with associated safety
186-
/// assertions.
187-
///
188-
/// Implementation: rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs?q=function:generate_record
189-
fn generate_record(&self, record: Rc<Record>) -> Result<ApiSnippets> {
190-
(self.codegen_functions().generate_record)(self, record)
191-
}
185+
/// Returns the generated bindings for the given record, along with associated safety
186+
/// assertions.
187+
///
188+
/// Implementation: rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs?q=function:generate_record
189+
pub fn generate_record(&self, record: Rc<Record>) -> Result<ApiSnippets> {
190+
(self.codegen_functions().generate_record)(self, record)
191+
}
192192

193-
#[provided]
194-
/// Returns the Rust type kind of the given C++ type.
195-
///
196-
/// This differs from `rs_type_kind_with_lifetime_elision` in that it replaces references
197-
/// with missing lifetimes with pointer types.
198-
fn rs_type_kind(&self, cc_type: CcType) -> Result<RsTypeKind> {
199-
self.rs_type_kind_with_lifetime_elision(cc_type, LifetimeOptions::default())
193+
/// Returns the Rust type kind of the given C++ type.
194+
///
195+
/// This differs from `rs_type_kind_with_lifetime_elision` in that it replaces references
196+
/// with missing lifetimes with pointer types.
197+
pub fn rs_type_kind(&self, cc_type: CcType) -> Result<RsTypeKind> {
198+
self.rs_type_kind_with_lifetime_elision(cc_type, LifetimeOptions::default())
199+
}
200+
201+
/// Returns true if an ItemId refers to a function that cannot receive bindings, because
202+
/// it is overloaded and ambiguous.
203+
///
204+
/// This does not include functions that are overloaded, where all but one overload is
205+
/// deprecated.
206+
pub fn is_ambiguous_function(&self, function_id: &FunctionId, item_id: ir::ItemId) -> bool {
207+
match self.overload_sets().get(function_id) {
208+
None => false,
209+
Some(id) => *id != Some(item_id),
200210
}
211+
}
201212

202-
#[provided]
203-
/// Returns true if an ItemId refers to a function that cannot receive bindings, because
204-
/// it is overloaded and ambiguous.
205-
///
206-
/// This does not include functions that are overloaded, where all but one overload is
207-
/// deprecated.
208-
fn is_ambiguous_function(&self, function_id: &FunctionId, item_id: ir::ItemId) -> bool {
209-
match self.overload_sets().get(function_id) {
210-
None => false,
211-
Some(id) => *id != Some(item_id),
213+
/// Returns the `Visibility` of the `rs_type_kind` in the given `library`.
214+
pub fn type_visibility(
215+
&self,
216+
library: &BazelLabel,
217+
rs_type_kind: RsTypeKind,
218+
) -> Result<Visibility> {
219+
match self.type_target_restriction(rs_type_kind.clone())? {
220+
Some(label) if &label != library => {
221+
let rs_type_kind = rs_type_kind.display(self);
222+
Err(anyhow!("{rs_type_kind} is `pub(crate)` in {label}"))
223+
}
224+
Some(_) => Ok(Visibility::PubCrate),
225+
None => {
226+
for subtype in rs_type_kind.dfs_iter() {
227+
if let RsTypeKind::Error { visibility_override, .. } = subtype {
228+
return Ok(visibility_override.unwrap_or(Visibility::PubCrate));
229+
}
230+
}
231+
Ok(Visibility::Public)
212232
}
213233
}
234+
}
235+
}
214236

215-
#[provided]
216-
/// Returns the `Visibility` of the `rs_type_kind` in the given `library`.
217-
fn type_visibility(&self, library: &BazelLabel, rs_type_kind: RsTypeKind) -> Result<Visibility> {
218-
match self.type_target_restriction(rs_type_kind.clone())? {
219-
Some(label) if &label != library => {
220-
let rs_type_kind = rs_type_kind.display(self);
221-
Err(anyhow!("{rs_type_kind} is `pub(crate)` in {label}"))
237+
impl<'db> BindingsGenerator<'db> {
238+
pub fn defining_target(&self, item_id: ir::ItemId) -> Option<ir::BazelLabel> {
239+
let ir = self.ir();
240+
let item = ir.find_untyped_decl(item_id);
241+
match item {
242+
ir::Item::Func(f) => {
243+
if let Some(parent_id) = f.enclosing_item_id {
244+
if let Ok(record) = ir.find_decl::<std::rc::Rc<ir::Record>>(parent_id) {
245+
return self.defining_target(record.id);
246+
}
222247
}
223-
Some(_) => Ok(Visibility::PubCrate),
224-
None => {
225-
for subtype in rs_type_kind.dfs_iter() {
226-
if let RsTypeKind::Error { visibility_override, .. } = subtype {
227-
return Ok(visibility_override.unwrap_or(Visibility::PubCrate));
248+
None
249+
}
250+
ir::Item::Record(r) => {
251+
r.template_specialization.as_ref().map(|ts| ts.defining_target.clone())
252+
}
253+
ir::Item::UnsupportedItem(ui) => ui.defining_target.clone(),
254+
_ => None,
255+
}
256+
}
257+
258+
pub fn debug_name(&self, item_id: ir::ItemId) -> std::rc::Rc<str> {
259+
let ir = self.ir();
260+
let item = ir.find_untyped_decl(item_id);
261+
match item {
262+
ir::Item::Func(f) => {
263+
let mut name = ir.namespace_qualifier_from_id(f.id).format_for_cc_debug();
264+
let record_name = || -> Option<std::rc::Rc<str>> {
265+
if let Some(parent_id) = f.enclosing_item_id {
266+
match ir.find_untyped_decl(parent_id) {
267+
ir::Item::ExistingRustType(existing_rust_type) => {
268+
Some(existing_rust_type.cc_name.clone())
269+
}
270+
ir::Item::Record(record) => Some(record.cc_name.identifier.clone()),
271+
ir::Item::IncompleteRecord(record) => {
272+
Some(record.cc_name.identifier.clone())
273+
}
274+
_ => None,
228275
}
276+
} else {
277+
None
278+
}
279+
};
280+
281+
match &f.cc_name {
282+
ir::UnqualifiedIdentifier::Identifier(id) => {
283+
name.push_str(&id.identifier);
284+
}
285+
ir::UnqualifiedIdentifier::Operator(op) => {
286+
name.push_str(&op.cc_name());
287+
}
288+
ir::UnqualifiedIdentifier::Destructor => {
289+
name.push('~');
290+
name.push_str(
291+
&record_name().expect("destructor must be associated with a record"),
292+
);
293+
}
294+
ir::UnqualifiedIdentifier::Constructor => {
295+
name.push_str(
296+
&record_name().expect("constructor must be associated with a record"),
297+
);
229298
}
230-
Ok(Visibility::Public)
231299
}
300+
name.into()
301+
}
302+
ir::Item::Comment(c) => format!(
303+
"<[internal] comment at {}>",
304+
c.source_loc().as_deref().unwrap_or("<unknown loc>")
305+
)
306+
.into(),
307+
ir::Item::UseMod(u) => {
308+
format!("<[internal] use mod {}::* = {}>", u.mod_name, u.path).into()
232309
}
310+
ir::Item::ExistingRustType(e) => format!(
311+
"{}{}",
312+
ir.namespace_qualifier_from_id(e.id).format_for_cc_debug(),
313+
e.cc_name
314+
)
315+
.into(),
316+
ir::Item::UnsupportedItem(ui) => ui.name.clone(),
317+
ir::Item::Namespace(n) => format!(
318+
"{}{}",
319+
ir.namespace_qualifier_from_id(n.id).format_for_cc_debug(),
320+
n.rs_name.identifier
321+
)
322+
.into(),
323+
ir::Item::IncompleteRecord(r) => format!(
324+
"{}{}",
325+
ir.namespace_qualifier_from_id(r.id).format_for_cc_debug(),
326+
r.cc_name.identifier
327+
)
328+
.into(),
329+
ir::Item::Record(r) => format!(
330+
"{}{}",
331+
ir.namespace_qualifier_from_id(r.id).format_for_cc_debug(),
332+
r.cc_name.identifier
333+
)
334+
.into(),
335+
ir::Item::Enum(e) => format!(
336+
"{}{}",
337+
ir.namespace_qualifier_from_id(e.id).format_for_cc_debug(),
338+
e.cc_name.identifier
339+
)
340+
.into(),
341+
ir::Item::Constant(c) => format!(
342+
"{}{}",
343+
ir.namespace_qualifier_from_id(c.id).format_for_cc_debug(),
344+
c.cc_name.identifier
345+
)
346+
.into(),
347+
ir::Item::GlobalVar(g) => format!(
348+
"{}{}",
349+
ir.namespace_qualifier_from_id(g.id).format_for_cc_debug(),
350+
g.cc_name.identifier
351+
)
352+
.into(),
353+
ir::Item::TypeAlias(t) => format!(
354+
"{}{}",
355+
ir.namespace_qualifier_from_id(t.id).format_for_cc_debug(),
356+
t.cc_name.identifier
357+
)
358+
.into(),
233359
}
234360
}
361+
362+
pub fn new_unsupported_item(
363+
&self,
364+
item: &impl GenericItem,
365+
path: Option<ir::UnsupportedItemPath>,
366+
error: Option<Rc<ir::FormattedError>>,
367+
cause: Option<Error>,
368+
must_bind: bool,
369+
) -> ir::UnsupportedItem {
370+
ir::UnsupportedItem::new_raw(
371+
self.debug_name(item.id()),
372+
item.unique_name(),
373+
item.unsupported_kind(),
374+
item.id(),
375+
item.source_loc(),
376+
self.defining_target(item.id()),
377+
must_bind,
378+
path,
379+
error,
380+
cause,
381+
)
382+
}
383+
384+
pub fn new_unsupported_item_with_static_message(
385+
&self,
386+
item: &impl GenericItem,
387+
path: Option<ir::UnsupportedItemPath>,
388+
message: &'static str,
389+
) -> ir::UnsupportedItem {
390+
self.new_unsupported_item(
391+
item,
392+
path,
393+
Some(Rc::new(ir::FormattedError { fmt: message.into(), message: message.into() })),
394+
None,
395+
item.must_bind(),
396+
)
397+
}
398+
399+
pub fn new_unsupported_item_with_cause(
400+
&self,
401+
item: &impl GenericItem,
402+
path: Option<ir::UnsupportedItemPath>,
403+
cause: Error,
404+
) -> ir::UnsupportedItem {
405+
self.new_unsupported_item(item, path, None, Some(cause), item.must_bind())
406+
}
407+
408+
pub fn error_item_name(&self, item_id: ir::ItemId) -> error_report::ItemName {
409+
let name = self.debug_name(item_id);
410+
let item = self.ir().find_untyped_decl(item_id);
411+
error_report::ItemName {
412+
name,
413+
id: item.id().as_u64(),
414+
unique_name: item.unique_name(),
415+
defining_target: self
416+
.defining_target(item.id())
417+
.map(|ir::BazelLabel(label)| std::rc::Rc::clone(&label)),
418+
}
419+
}
420+
421+
pub fn error_scope<'a>(&'a self, item_id: ir::ItemId) -> Option<error_report::ItemScope<'a>> {
422+
let item = self.ir().find_untyped_decl(item_id);
423+
if matches!(item, ir::Item::Comment(_) | ir::Item::UseMod(_)) {
424+
None
425+
} else {
426+
Some(error_report::ItemScope::new(self.errors(), self.error_item_name(item_id)))
427+
}
428+
}
429+
430+
pub fn assert_in_error_scope(&self, item_id: ir::ItemId) {
431+
self.errors().assert_in_item(self.error_item_name(item_id));
432+
}
235433
}

0 commit comments

Comments
 (0)