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}