1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use std::io::Write;
6 
7 use syn;
8 
9 use crate::bindgen::config::{Config, Language, LayoutConfig};
10 use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
11 use crate::bindgen::dependencies::Dependencies;
12 use crate::bindgen::ir::{
13     AnnotationSet, Cfg, ConditionWrite, Constant, Documentation, GenericParams, Item,
14     ItemContainer, Path, Repr, ReprAlign, ReprStyle, ToCondition, Type, Typedef,
15 };
16 use crate::bindgen::library::Library;
17 use crate::bindgen::mangle;
18 use crate::bindgen::monomorph::Monomorphs;
19 use crate::bindgen::rename::{IdentifierType, RenameRule};
20 use crate::bindgen::reserved;
21 use crate::bindgen::utilities::{find_first_some, IterHelpers};
22 use crate::bindgen::writer::{ListType, Source, SourceWriter};
23 
24 #[derive(Debug, Clone)]
25 pub struct Struct {
26     pub path: Path,
27     pub export_name: String,
28     pub generic_params: GenericParams,
29     pub fields: Vec<(String, Type, Documentation)>,
30     /// Whether there's a tag field on the body of this struct. When this is
31     /// true, is_enum_variant_body is also guaranteed to be true.
32     pub is_tagged: bool,
33     /// Whether this is an enum variant body.
34     pub is_enum_variant_body: bool,
35     pub alignment: Option<ReprAlign>,
36     pub is_transparent: bool,
37     pub tuple_struct: bool,
38     pub cfg: Option<Cfg>,
39     pub annotations: AnnotationSet,
40     pub documentation: Documentation,
41     pub associated_constants: Vec<Constant>,
42 }
43 
44 impl Struct {
45     /// Whether this struct can derive operator== / operator!=.
can_derive_eq(&self) -> bool46     pub fn can_derive_eq(&self) -> bool {
47         !self.fields.is_empty() && self.fields.iter().all(|x| x.1.can_cmp_eq())
48     }
49 
add_associated_constant(&mut self, c: Constant)50     pub fn add_associated_constant(&mut self, c: Constant) {
51         self.associated_constants.push(c);
52     }
53 
load( layout_config: &LayoutConfig, item: &syn::ItemStruct, mod_cfg: Option<&Cfg>, ) -> Result<Self, String>54     pub fn load(
55         layout_config: &LayoutConfig,
56         item: &syn::ItemStruct,
57         mod_cfg: Option<&Cfg>,
58     ) -> Result<Self, String> {
59         let repr = Repr::load(&item.attrs)?;
60         let is_transparent = match repr.style {
61             ReprStyle::C => false,
62             ReprStyle::Transparent => true,
63             _ => {
64                 return Err("Struct is not marked #[repr(C)] or #[repr(transparent)].".to_owned());
65             }
66         };
67 
68         let path = Path::new(item.ident.to_string());
69 
70         // Ensure we can safely represent the struct given the configuration.
71         if let Some(align) = repr.align {
72             layout_config.ensure_safe_to_represent(&align)?;
73         }
74 
75         let (fields, tuple_struct) = match item.fields {
76             syn::Fields::Unit => (Vec::new(), false),
77             syn::Fields::Named(ref fields) => {
78                 let out = fields
79                     .named
80                     .iter()
81                     .try_skip_map(|x| x.as_ident_and_type(&path))?;
82                 (out, false)
83             }
84             syn::Fields::Unnamed(ref fields) => {
85                 let mut out = Vec::new();
86                 let mut current = 0;
87                 for field in fields.unnamed.iter() {
88                     if let Some(mut x) = Type::load(&field.ty)? {
89                         x.replace_self_with(&path);
90                         out.push((format!("{}", current), x, Documentation::load(&field.attrs)));
91                         current += 1;
92                     }
93                 }
94                 (out, true)
95             }
96         };
97 
98         let is_tagged = false;
99         let is_enum_variant_body = false;
100 
101         Ok(Struct::new(
102             path,
103             GenericParams::new(&item.generics),
104             fields,
105             is_tagged,
106             is_enum_variant_body,
107             repr.align,
108             is_transparent,
109             tuple_struct,
110             Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
111             AnnotationSet::load(&item.attrs)?,
112             Documentation::load(&item.attrs),
113         ))
114     }
115 
new( path: Path, generic_params: GenericParams, fields: Vec<(String, Type, Documentation)>, is_tagged: bool, is_enum_variant_body: bool, alignment: Option<ReprAlign>, is_transparent: bool, tuple_struct: bool, cfg: Option<Cfg>, annotations: AnnotationSet, documentation: Documentation, ) -> Self116     pub fn new(
117         path: Path,
118         generic_params: GenericParams,
119         fields: Vec<(String, Type, Documentation)>,
120         is_tagged: bool,
121         is_enum_variant_body: bool,
122         alignment: Option<ReprAlign>,
123         is_transparent: bool,
124         tuple_struct: bool,
125         cfg: Option<Cfg>,
126         annotations: AnnotationSet,
127         documentation: Documentation,
128     ) -> Self {
129         let export_name = path.name().to_owned();
130         Self {
131             path,
132             export_name,
133             generic_params,
134             fields,
135             is_tagged,
136             is_enum_variant_body,
137             alignment,
138             is_transparent,
139             tuple_struct,
140             cfg,
141             annotations,
142             documentation,
143             associated_constants: vec![],
144         }
145     }
146 
simplify_standard_types(&mut self)147     pub fn simplify_standard_types(&mut self) {
148         for &mut (_, ref mut ty, _) in &mut self.fields {
149             ty.simplify_standard_types();
150         }
151     }
152 
is_generic(&self) -> bool153     pub fn is_generic(&self) -> bool {
154         self.generic_params.len() > 0
155     }
156 
add_monomorphs(&self, library: &Library, out: &mut Monomorphs)157     pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
158         // Generic structs can instantiate monomorphs only once they've been
159         // instantiated. See `instantiate_monomorph` for more details.
160         if self.is_generic() {
161             return;
162         }
163 
164         for &(_, ref ty, _) in &self.fields {
165             ty.add_monomorphs(library, out);
166         }
167     }
168 
mangle_paths(&mut self, monomorphs: &Monomorphs)169     pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
170         for &mut (_, ref mut ty, _) in &mut self.fields {
171             ty.mangle_paths(monomorphs);
172         }
173     }
174 
specialize(&self, generic_values: &[Type], mappings: &[(&Path, &Type)]) -> Self175     pub fn specialize(&self, generic_values: &[Type], mappings: &[(&Path, &Type)]) -> Self {
176         let mangled_path = mangle::mangle_path(&self.path, generic_values);
177         Struct::new(
178             mangled_path,
179             GenericParams::default(),
180             self.fields
181                 .iter()
182                 .map(|x| (x.0.clone(), x.1.specialize(mappings), x.2.clone()))
183                 .collect(),
184             self.is_tagged,
185             self.is_enum_variant_body,
186             self.alignment,
187             self.is_transparent,
188             self.tuple_struct,
189             self.cfg.clone(),
190             self.annotations.clone(),
191             self.documentation.clone(),
192         )
193     }
194 
emit_bitflags_binop<F: Write>( &self, operator: char, other: &str, out: &mut SourceWriter<F>, )195     fn emit_bitflags_binop<F: Write>(
196         &self,
197         operator: char,
198         other: &str,
199         out: &mut SourceWriter<F>,
200     ) {
201         out.new_line();
202         write!(
203             out,
204             "{} operator{}(const {}& {}) const",
205             self.export_name(),
206             operator,
207             self.export_name(),
208             other
209         );
210         out.open_brace();
211         write!(
212             out,
213             "return {{static_cast<decltype(bits)>(this->bits {} {}.bits)}};",
214             operator, other
215         );
216         out.close_brace(false);
217 
218         out.new_line();
219         write!(
220             out,
221             "{}& operator{}=(const {}& {})",
222             self.export_name(),
223             operator,
224             self.export_name(),
225             other
226         );
227         out.open_brace();
228         write!(out, "*this = (*this {} {});", operator, other);
229         out.new_line();
230         write!(out, "return *this;");
231         out.close_brace(false);
232     }
233 }
234 
235 impl Item for Struct {
path(&self) -> &Path236     fn path(&self) -> &Path {
237         &self.path
238     }
239 
export_name(&self) -> &str240     fn export_name(&self) -> &str {
241         &self.export_name
242     }
243 
cfg(&self) -> Option<&Cfg>244     fn cfg(&self) -> Option<&Cfg> {
245         self.cfg.as_ref()
246     }
247 
annotations(&self) -> &AnnotationSet248     fn annotations(&self) -> &AnnotationSet {
249         &self.annotations
250     }
251 
annotations_mut(&mut self) -> &mut AnnotationSet252     fn annotations_mut(&mut self) -> &mut AnnotationSet {
253         &mut self.annotations
254     }
255 
container(&self) -> ItemContainer256     fn container(&self) -> ItemContainer {
257         ItemContainer::Struct(self.clone())
258     }
259 
collect_declaration_types(&self, resolver: &mut DeclarationTypeResolver)260     fn collect_declaration_types(&self, resolver: &mut DeclarationTypeResolver) {
261         if !self.is_transparent {
262             resolver.add_struct(&self.path);
263         }
264     }
265 
resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver)266     fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
267         for &mut (_, ref mut ty, _) in &mut self.fields {
268             ty.resolve_declaration_types(resolver);
269         }
270     }
271 
rename_for_config(&mut self, config: &Config)272     fn rename_for_config(&mut self, config: &Config) {
273         // Rename the name of the struct
274         if !self.is_tagged || config.language == Language::C {
275             config.export.rename(&mut self.export_name);
276         }
277 
278         // Rename the types used in fields
279         {
280             let fields = self
281                 .fields
282                 .iter_mut()
283                 .skip(if self.is_tagged { 1 } else { 0 });
284             for &mut (_, ref mut ty, _) in fields {
285                 ty.rename_for_config(config, &self.generic_params);
286             }
287         }
288 
289         // Apply renaming rules to fields in the following order
290         //   1. `cbindgen::field-names` annotation
291         //   2. `cbindgen::rename-all` annotation
292         //   3. config struct rename rule
293         // If the struct is a tuple struct and we have not renamed the
294         // fields, then prefix each of them with an underscore.
295         // If any field is a reserved keyword, then postfix it with an
296         // underscore.
297 
298         // Scope for mutable borrow of fields
299         {
300             let mut names = self.fields.iter_mut().map(|field| &mut field.0);
301 
302             let field_rules = [
303                 self.annotations.parse_atom::<RenameRule>("rename-all"),
304                 config.structure.rename_fields,
305             ];
306 
307             if let Some(o) = self.annotations.list("field-names") {
308                 for (dest, src) in names.zip(o) {
309                     *dest = src;
310                 }
311             } else if let Some(r) = find_first_some(&field_rules) {
312                 for name in names {
313                     *name = r.apply(name, IdentifierType::StructMember);
314                 }
315             } else if self.tuple_struct {
316                 // If there is a tag field, skip it
317                 if self.is_tagged {
318                     names.next();
319                 }
320 
321                 // If we don't have any rules for a tuple struct, prefix them with
322                 // an underscore so it still compiles
323                 for name in names {
324                     name.insert(0, '_');
325                 }
326             }
327         }
328 
329         for field in &mut self.fields {
330             reserved::escape(&mut field.0);
331         }
332 
333         for c in self.associated_constants.iter_mut() {
334             c.rename_for_config(config);
335         }
336     }
337 
add_dependencies(&self, library: &Library, out: &mut Dependencies)338     fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
339         let mut fields = self.fields.iter();
340 
341         // If there is a tag field, skip it
342         if self.is_tagged {
343             fields.next();
344         }
345 
346         for &(_, ref ty, _) in fields {
347             ty.add_dependencies_ignoring_generics(&self.generic_params, library, out);
348         }
349 
350         for c in &self.associated_constants {
351             c.add_dependencies(library, out);
352         }
353     }
354 
instantiate_monomorph( &self, generic_values: &[Type], library: &Library, out: &mut Monomorphs, )355     fn instantiate_monomorph(
356         &self,
357         generic_values: &[Type],
358         library: &Library,
359         out: &mut Monomorphs,
360     ) {
361         assert!(
362             self.generic_params.len() > 0,
363             "{} is not generic",
364             self.path
365         );
366         assert!(
367             self.generic_params.len() == generic_values.len(),
368             "{} has {} params but is being instantiated with {} values",
369             self.path,
370             self.generic_params.len(),
371             generic_values.len(),
372         );
373 
374         let mappings = self
375             .generic_params
376             .iter()
377             .zip(generic_values.iter())
378             .collect::<Vec<_>>();
379 
380         let monomorph = self.specialize(generic_values, &mappings);
381 
382         // Instantiate any monomorphs for any generic paths we may have just created.
383         monomorph.add_monomorphs(library, out);
384 
385         out.insert_struct(self, monomorph, generic_values.to_owned());
386     }
387 }
388 
389 impl Source for Struct {
write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>)390     fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
391         if self.is_transparent {
392             let typedef = Typedef {
393                 path: self.path.clone(),
394                 export_name: self.export_name.to_owned(),
395                 generic_params: self.generic_params.clone(),
396                 aliased: self.fields[0].1.clone(),
397                 cfg: self.cfg.clone(),
398                 annotations: self.annotations.clone(),
399                 documentation: self.documentation.clone(),
400             };
401             typedef.write(config, out);
402             for constant in &self.associated_constants {
403                 out.new_line();
404                 constant.write(config, out, Some(self));
405             }
406             return;
407         }
408 
409         let condition = self.cfg.to_condition(config);
410         condition.write_before(config, out);
411 
412         self.documentation.write(config, out);
413 
414         if !self.is_enum_variant_body {
415             self.generic_params.write(config, out);
416         }
417 
418         // The following results in
419         // C++ or C with Tag as style:
420         //   struct Name {
421         // C with Type only style:
422         //   typedef struct {
423         // C with Both as style:
424         //   typedef struct Name {
425         if config.language == Language::C && config.style.generate_typedef() {
426             out.write("typedef ");
427         }
428 
429         out.write("struct");
430 
431         if let Some(align) = self.alignment {
432             match align {
433                 ReprAlign::Packed => {
434                     if let Some(ref anno) = config.layout.packed {
435                         write!(out, " {}", anno);
436                     }
437                 }
438                 ReprAlign::Align(n) => {
439                     if let Some(ref anno) = config.layout.aligned_n {
440                         write!(out, " {}({})", anno, n);
441                     }
442                 }
443             }
444         }
445 
446         if self.annotations.must_use {
447             if let Some(ref anno) = config.structure.must_use {
448                 write!(out, " {}", anno);
449             }
450         }
451 
452         if config.language == Language::Cxx || config.style.generate_tag() {
453             write!(out, " {}", self.export_name());
454         }
455 
456         out.open_brace();
457 
458         // Emit the pre_body section, if relevant
459         if let Some(body) = config.export.pre_body(&self.path) {
460             out.write_raw_block(body);
461             out.new_line();
462         }
463 
464         if config.documentation {
465             out.write_vertical_source_list(&self.fields, ListType::Cap(";"));
466         } else {
467             let vec: Vec<_> = self
468                 .fields
469                 .iter()
470                 .map(|&(ref name, ref ty, _)| (name.clone(), ty.clone()))
471                 .collect();
472             out.write_vertical_source_list(&vec[..], ListType::Cap(";"));
473         }
474 
475         if config.language == Language::Cxx {
476             let mut wrote_start_newline = false;
477 
478             if config.structure.derive_constructor(&self.annotations) && !self.fields.is_empty() {
479                 if !wrote_start_newline {
480                     wrote_start_newline = true;
481                     out.new_line();
482                 }
483 
484                 out.new_line();
485 
486                 let arg_renamer = |name: &str| {
487                     config
488                         .function
489                         .rename_args
490                         .as_ref()
491                         .unwrap_or(&RenameRule::GeckoCase)
492                         .apply(name, IdentifierType::FunctionArg)
493                 };
494                 write!(out, "{}(", self.export_name());
495                 let vec: Vec<_> = self
496                     .fields
497                     .iter()
498                     .map(|&(ref name, ref ty, _)| {
499                         // const-ref args to constructor
500                         (format!("const& {}", arg_renamer(name)), ty.clone())
501                     })
502                     .collect();
503                 out.write_vertical_source_list(&vec[..], ListType::Join(","));
504                 write!(out, ")");
505                 out.new_line();
506                 write!(out, "  : ");
507                 let vec: Vec<_> = self
508                     .fields
509                     .iter()
510                     .map(|x| format!("{}({})", x.0, arg_renamer(&x.0)))
511                     .collect();
512                 out.write_vertical_source_list(&vec[..], ListType::Join(","));
513                 out.new_line();
514                 write!(out, "{{}}");
515                 out.new_line();
516             }
517 
518             let other = if let Some(r) = config.function.rename_args {
519                 r.apply("other", IdentifierType::FunctionArg)
520             } else {
521                 String::from("other")
522             };
523 
524             if self
525                 .annotations
526                 .bool("internal-derive-bitflags")
527                 .unwrap_or(false)
528             {
529                 if !wrote_start_newline {
530                     wrote_start_newline = true;
531                     out.new_line();
532                 }
533                 out.new_line();
534                 write!(out, "explicit operator bool() const");
535                 out.open_brace();
536                 write!(out, "return !!bits;");
537                 out.close_brace(false);
538 
539                 out.new_line();
540                 write!(out, "{} operator~() const", self.export_name());
541                 out.open_brace();
542                 write!(out, "return {{static_cast<decltype(bits)>(~bits)}};");
543                 out.close_brace(false);
544 
545                 self.emit_bitflags_binop('|', &other, out);
546                 self.emit_bitflags_binop('&', &other, out);
547                 self.emit_bitflags_binop('^', &other, out);
548             }
549 
550             let skip_fields = if self.is_tagged { 1 } else { 0 };
551 
552             macro_rules! emit_op {
553                 ($op_name:expr, $op:expr, $conjuc:expr) => {{
554                     if !wrote_start_newline {
555                         #[allow(unused_assignments)]
556                         {
557                             wrote_start_newline = true;
558                         }
559                         out.new_line();
560                     }
561 
562                     out.new_line();
563 
564                     if let Some(Some(attrs)) =
565                         self.annotations.atom(concat!($op_name, "-attributes"))
566                     {
567                         write!(out, "{} ", attrs);
568                     }
569 
570                     write!(
571                         out,
572                         "bool operator{}(const {}& {}) const",
573                         $op,
574                         self.export_name(),
575                         other
576                     );
577                     out.open_brace();
578                     out.write("return ");
579                     let vec: Vec<_> = self
580                         .fields
581                         .iter()
582                         .skip(skip_fields)
583                         .map(|x| format!("{} {} {}.{}", x.0, $op, other, x.0))
584                         .collect();
585                     out.write_vertical_source_list(
586                         &vec[..],
587                         ListType::Join(&format!(" {}", $conjuc)),
588                     );
589                     out.write(";");
590                     out.close_brace(false);
591                 }};
592             };
593 
594             if config.structure.derive_eq(&self.annotations) && self.can_derive_eq() {
595                 emit_op!("eq", "==", "&&");
596             }
597             if config.structure.derive_neq(&self.annotations) && self.can_derive_eq() {
598                 emit_op!("neq", "!=", "||");
599             }
600             if config.structure.derive_lt(&self.annotations)
601                 && self.fields.len() == 1
602                 && self.fields[0].1.can_cmp_order()
603             {
604                 emit_op!("lt", "<", "&&");
605             }
606             if config.structure.derive_lte(&self.annotations)
607                 && self.fields.len() == 1
608                 && self.fields[0].1.can_cmp_order()
609             {
610                 emit_op!("lte", "<=", "&&");
611             }
612             if config.structure.derive_gt(&self.annotations)
613                 && self.fields.len() == 1
614                 && self.fields[0].1.can_cmp_order()
615             {
616                 emit_op!("gt", ">", "&&");
617             }
618             if config.structure.derive_gte(&self.annotations)
619                 && self.fields.len() == 1
620                 && self.fields[0].1.can_cmp_order()
621             {
622                 emit_op!("gte", ">=", "&&");
623             }
624         }
625 
626         // Emit the post_body section, if relevant
627         if let Some(body) = config.export.post_body(&self.path) {
628             out.new_line();
629             out.write_raw_block(body);
630         }
631 
632         if config.language == Language::Cxx
633             && config.structure.associated_constants_in_body
634             && config.constant.allow_static_const
635         {
636             for constant in &self.associated_constants {
637                 out.new_line();
638                 constant.write_declaration(config, out, self);
639             }
640         }
641 
642         if config.language == Language::C && config.style.generate_typedef() {
643             out.close_brace(false);
644             write!(out, " {};", self.export_name());
645         } else {
646             out.close_brace(true);
647         }
648 
649         for constant in &self.associated_constants {
650             out.new_line();
651             constant.write(config, out, Some(self));
652         }
653 
654         condition.write_after(config, out);
655     }
656 }
657 
658 pub trait SynFieldHelpers {
as_ident_and_type( &self, self_path: &Path, ) -> Result<Option<(String, Type, Documentation)>, String>659     fn as_ident_and_type(
660         &self,
661         self_path: &Path,
662     ) -> Result<Option<(String, Type, Documentation)>, String>;
663 }
664 
665 impl SynFieldHelpers for syn::Field {
as_ident_and_type( &self, self_path: &Path, ) -> Result<Option<(String, Type, Documentation)>, String>666     fn as_ident_and_type(
667         &self,
668         self_path: &Path,
669     ) -> Result<Option<(String, Type, Documentation)>, String> {
670         let ident = self
671             .ident
672             .as_ref()
673             .ok_or_else(|| "field is missing identifier".to_string())?
674             .clone();
675         let converted_ty = Type::load(&self.ty)?;
676 
677         if let Some(mut x) = converted_ty {
678             x.replace_self_with(self_path);
679             Ok(Some((
680                 ident.to_string(),
681                 x,
682                 Documentation::load(&self.attrs),
683             )))
684         } else {
685             Ok(None)
686         }
687     }
688 }
689