@@ -7,11 +7,11 @@ use crate::code_snippet::{
77} ;
88use crate :: function_types:: { FunctionId , GeneratedFunction , ImplKind } ;
99use crate :: rs_snippet:: { LifetimeOptions , RsTypeKind , Safety } ;
10- use arc_anyhow:: { anyhow, Result } ;
10+ use arc_anyhow:: { anyhow, Error , Result } ;
1111use crubit_abi_type:: CrubitAbiType ;
1212use error_report:: { ErrorReporting , ReportFatalError } ;
1313use 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 } ;
1515use proc_macro2:: Ident ;
1616use std:: collections:: HashMap ;
1717use 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