bindgen/ir/
annotations.rs

1//! Types and functions related to bindgen annotation comments.
2//!
3//! Users can add annotations in doc comments to types that they would like to
4//! replace other types with, mark as opaque, etc. This module deals with all of
5//! that stuff.
6
7use std::str::FromStr;
8
9use crate::clang;
10
11/// What kind of visibility modifier should be used for a struct or field?
12#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Default)]
13pub enum FieldVisibilityKind {
14    /// Fields are marked as private, i.e., struct Foo {bar: bool}
15    Private,
16    /// Fields are marked as crate public, i.e., struct Foo {pub(crate) bar: bool}
17    PublicCrate,
18    /// Fields are marked as public, i.e., struct Foo {pub bar: bool}
19    #[default]
20    Public,
21}
22
23impl FromStr for FieldVisibilityKind {
24    type Err = String;
25
26    fn from_str(s: &str) -> Result<Self, Self::Err> {
27        match s {
28            "private" => Ok(Self::Private),
29            "crate" => Ok(Self::PublicCrate),
30            "public" => Ok(Self::Public),
31            _ => Err(format!("Invalid visibility kind: `{s}`")),
32        }
33    }
34}
35
36impl std::fmt::Display for FieldVisibilityKind {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        let s = match self {
39            FieldVisibilityKind::Private => "private",
40            FieldVisibilityKind::PublicCrate => "crate",
41            FieldVisibilityKind::Public => "public",
42        };
43
44        s.fmt(f)
45    }
46}
47
48/// What kind of accessor should we provide for a field?
49#[derive(Copy, PartialEq, Eq, Clone, Debug)]
50pub(crate) enum FieldAccessorKind {
51    /// No accessor.
52    None,
53    /// Plain accessor.
54    Regular,
55    /// Unsafe accessor.
56    Unsafe,
57    /// Immutable accessor.
58    Immutable,
59}
60
61/// Annotations for a given item, or a field.
62///
63/// You can see the kind of comments that are accepted in the [Doxygen documentation](https://www.doxygen.nl/manual/docblocks.html).
64#[derive(Default, Clone, PartialEq, Eq, Debug)]
65pub(crate) struct Annotations {
66    /// Whether this item is marked as opaque. Only applies to types.
67    opaque: bool,
68    /// Whether this item should be hidden from the output. Only applies to
69    /// types, or enum variants.
70    hide: bool,
71    /// Whether this type should be replaced by another. The name is a
72    /// namespace-aware path.
73    use_instead_of: Option<Vec<String>>,
74    /// Manually disable deriving copy/clone on this type. Only applies to
75    /// struct or union types.
76    disallow_copy: bool,
77    /// Manually disable deriving debug on this type.
78    disallow_debug: bool,
79    /// Manually disable deriving/implement default on this type.
80    disallow_default: bool,
81    /// Whether to add a `#[must_use]` annotation to this type.
82    must_use_type: bool,
83    /// Visibility of struct fields. You can set this on
84    /// structs (it will apply to all the fields), or individual fields.
85    visibility_kind: Option<FieldVisibilityKind>,
86    /// The kind of accessor this field will have. Also can be applied to
87    /// structs so all the fields inside share it by default.
88    accessor_kind: Option<FieldAccessorKind>,
89    /// Whether this enum variant should be constified.
90    ///
91    /// This is controlled by the `constant` attribute, this way:
92    ///
93    /// ```cpp
94    /// enum Foo {
95    ///     Bar = 0, /**< <div rustbindgen constant></div> */
96    ///     Baz = 0,
97    /// };
98    /// ```
99    ///
100    /// In that case, bindgen will generate a constant for `Bar` instead of
101    /// `Baz`.
102    constify_enum_variant: bool,
103    /// List of explicit derives for this type.
104    derives: Vec<String>,
105    /// List of explicit attributes for this type.
106    attributes: Vec<String>,
107}
108
109fn parse_accessor(s: &str) -> FieldAccessorKind {
110    match s {
111        "false" => FieldAccessorKind::None,
112        "unsafe" => FieldAccessorKind::Unsafe,
113        "immutable" => FieldAccessorKind::Immutable,
114        _ => FieldAccessorKind::Regular,
115    }
116}
117
118impl Annotations {
119    /// Construct new annotations for the given cursor and its bindgen comments
120    /// (if any).
121    pub(crate) fn new(cursor: &clang::Cursor) -> Option<Annotations> {
122        let mut anno = Annotations::default();
123        let mut matched_one = false;
124        anno.parse(&cursor.comment(), &mut matched_one);
125
126        if matched_one {
127            Some(anno)
128        } else {
129            None
130        }
131    }
132
133    /// Should this type be hidden?
134    pub(crate) fn hide(&self) -> bool {
135        self.hide
136    }
137
138    /// Should this type be opaque?
139    pub(crate) fn opaque(&self) -> bool {
140        self.opaque
141    }
142
143    /// For a given type, indicates the type it should replace.
144    ///
145    /// For example, in the following code:
146    ///
147    /// ```cpp
148    ///
149    /// /** <div rustbindgen replaces="Bar"></div> */
150    /// struct Foo { int x; };
151    ///
152    /// struct Bar { char foo; };
153    /// ```
154    ///
155    /// the generated code would look something like:
156    ///
157    /// ```
158    /// /** <div rustbindgen replaces="Bar"></div> */
159    /// struct Bar {
160    ///     x: ::std::os::raw::c_int,
161    /// };
162    /// ```
163    ///
164    /// That is, code for `Foo` is used to generate `Bar`.
165    pub(crate) fn use_instead_of(&self) -> Option<&[String]> {
166        self.use_instead_of.as_deref()
167    }
168
169    /// The list of derives that have been specified in this annotation.
170    pub(crate) fn derives(&self) -> &[String] {
171        &self.derives
172    }
173
174    /// The list of attributes that have been specified in this annotation.
175    pub(crate) fn attributes(&self) -> &[String] {
176        &self.attributes
177    }
178
179    /// Should we avoid implementing the `Copy` trait?
180    pub(crate) fn disallow_copy(&self) -> bool {
181        self.disallow_copy
182    }
183
184    /// Should we avoid implementing the `Debug` trait?
185    pub(crate) fn disallow_debug(&self) -> bool {
186        self.disallow_debug
187    }
188
189    /// Should we avoid implementing the `Default` trait?
190    pub(crate) fn disallow_default(&self) -> bool {
191        self.disallow_default
192    }
193
194    /// Should this type get a `#[must_use]` annotation?
195    pub(crate) fn must_use_type(&self) -> bool {
196        self.must_use_type
197    }
198
199    /// What kind of accessors should we provide for this type's fields?
200    pub(crate) fn visibility_kind(&self) -> Option<FieldVisibilityKind> {
201        self.visibility_kind
202    }
203
204    /// What kind of accessors should we provide for this type's fields?
205    pub(crate) fn accessor_kind(&self) -> Option<FieldAccessorKind> {
206        self.accessor_kind
207    }
208
209    fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
210        use clang_sys::CXComment_HTMLStartTag;
211        if comment.kind() == CXComment_HTMLStartTag &&
212            comment.get_tag_name() == "div" &&
213            comment
214                .get_tag_attrs()
215                .next()
216                .is_some_and(|attr| attr.name == "rustbindgen")
217        {
218            *matched = true;
219            for attr in comment.get_tag_attrs() {
220                match attr.name.as_str() {
221                    "opaque" => self.opaque = true,
222                    "hide" => self.hide = true,
223                    "nocopy" => self.disallow_copy = true,
224                    "nodebug" => self.disallow_debug = true,
225                    "nodefault" => self.disallow_default = true,
226                    "mustusetype" => self.must_use_type = true,
227                    "replaces" => {
228                        self.use_instead_of = Some(
229                            attr.value.split("::").map(Into::into).collect(),
230                        );
231                    }
232                    "derive" => self.derives.push(attr.value),
233                    "attribute" => self.attributes.push(attr.value),
234                    "private" => {
235                        self.visibility_kind = if attr.value == "false" {
236                            Some(FieldVisibilityKind::Public)
237                        } else {
238                            Some(FieldVisibilityKind::Private)
239                        };
240                    }
241                    "accessor" => {
242                        self.accessor_kind = Some(parse_accessor(&attr.value));
243                    }
244                    "constant" => self.constify_enum_variant = true,
245                    _ => {}
246                }
247            }
248        }
249
250        for child in comment.get_children() {
251            self.parse(&child, matched);
252        }
253    }
254
255    /// Returns whether we've parsed a "constant" attribute.
256    pub(crate) fn constify_enum_variant(&self) -> bool {
257        self.constify_enum_variant
258    }
259}