1 | //! Bindgen's core intermediate representation type. |
2 | |
3 | use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME}; |
4 | use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult}; |
5 | use super::annotations::Annotations; |
6 | use super::comp::{CompKind, MethodKind}; |
7 | use super::context::{BindgenContext, ItemId, PartialType, TypeId}; |
8 | use super::derive::{ |
9 | CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq, |
10 | CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd, |
11 | }; |
12 | use super::dot::DotAttributes; |
13 | use super::function::{Function, FunctionKind}; |
14 | use super::item_kind::ItemKind; |
15 | use super::layout::Opaque; |
16 | use super::module::Module; |
17 | use super::template::{AsTemplateParam, TemplateParameters}; |
18 | use super::traversal::{EdgeKind, Trace, Tracer}; |
19 | use super::ty::{Type, TypeKind}; |
20 | use crate::clang; |
21 | use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; |
22 | |
23 | use lazycell::LazyCell; |
24 | |
25 | use std::cell::Cell; |
26 | use std::collections::BTreeSet; |
27 | use std::fmt::Write; |
28 | use std::io; |
29 | use std::iter; |
30 | |
31 | /// A trait to get the canonical name from an item. |
32 | /// |
33 | /// This is the trait that will eventually isolate all the logic related to name |
34 | /// mangling and that kind of stuff. |
35 | /// |
36 | /// This assumes no nested paths, at some point I'll have to make it a more |
37 | /// complex thing. |
38 | /// |
39 | /// This name is required to be safe for Rust, that is, is not expected to |
40 | /// return any rust keyword from here. |
41 | pub(crate) trait ItemCanonicalName { |
42 | /// Get the canonical name for this item. |
43 | fn canonical_name(&self, ctx: &BindgenContext) -> String; |
44 | } |
45 | |
46 | /// The same, but specifies the path that needs to be followed to reach an item. |
47 | /// |
48 | /// To contrast with canonical_name, here's an example: |
49 | /// |
50 | /// ```c++ |
51 | /// namespace foo { |
52 | /// const BAR = 3; |
53 | /// } |
54 | /// ``` |
55 | /// |
56 | /// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical |
57 | /// name is just `"BAR"`. |
58 | pub(crate) trait ItemCanonicalPath { |
59 | /// Get the namespace-aware canonical path for this item. This means that if |
60 | /// namespaces are disabled, you'll get a single item, and otherwise you get |
61 | /// the whole path. |
62 | fn namespace_aware_canonical_path( |
63 | &self, |
64 | ctx: &BindgenContext, |
65 | ) -> Vec<String>; |
66 | |
67 | /// Get the canonical path for this item. |
68 | fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>; |
69 | } |
70 | |
71 | /// A trait for determining if some IR thing is opaque or not. |
72 | pub(crate) trait IsOpaque { |
73 | /// Extra context the IR thing needs to determine if it is opaque or not. |
74 | type Extra; |
75 | |
76 | /// Returns `true` if the thing is opaque, and `false` otherwise. |
77 | /// |
78 | /// May only be called when `ctx` is in the codegen phase. |
79 | fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool; |
80 | } |
81 | |
82 | /// A trait for determining if some IR thing has type parameter in array or not. |
83 | pub(crate) trait HasTypeParamInArray { |
84 | /// Returns `true` if the thing has Array, and `false` otherwise. |
85 | fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool; |
86 | } |
87 | |
88 | /// A trait for determining if some IR thing has float or not. |
89 | pub(crate) trait HasFloat { |
90 | /// Returns `true` if the thing has float, and `false` otherwise. |
91 | fn has_float(&self, ctx: &BindgenContext) -> bool; |
92 | } |
93 | |
94 | /// A trait for iterating over an item and its parents and up its ancestor chain |
95 | /// up to (but not including) the implicit root module. |
96 | pub(crate) trait ItemAncestors { |
97 | /// Get an iterable over this item's ancestors. |
98 | fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>; |
99 | } |
100 | |
101 | #[cfg (feature = "__testing_only_extra_assertions" )] |
102 | type DebugOnlyItemSet = ItemSet; |
103 | |
104 | #[cfg (not(feature = "__testing_only_extra_assertions" ))] |
105 | struct DebugOnlyItemSet; |
106 | |
107 | #[cfg (not(feature = "__testing_only_extra_assertions" ))] |
108 | impl DebugOnlyItemSet { |
109 | fn new() -> Self { |
110 | DebugOnlyItemSet |
111 | } |
112 | |
113 | fn contains(&self, _id: &ItemId) -> bool { |
114 | false |
115 | } |
116 | |
117 | fn insert(&mut self, _id: ItemId) {} |
118 | } |
119 | |
120 | /// An iterator over an item and its ancestors. |
121 | pub(crate) struct ItemAncestorsIter<'a> { |
122 | item: ItemId, |
123 | ctx: &'a BindgenContext, |
124 | seen: DebugOnlyItemSet, |
125 | } |
126 | |
127 | impl<'a> ItemAncestorsIter<'a> { |
128 | fn new<Id: Into<ItemId>>(ctx: &'a BindgenContext, id: Id) -> Self { |
129 | ItemAncestorsIter { |
130 | item: id.into(), |
131 | ctx, |
132 | seen: DebugOnlyItemSet::new(), |
133 | } |
134 | } |
135 | } |
136 | |
137 | impl<'a> Iterator for ItemAncestorsIter<'a> { |
138 | type Item = ItemId; |
139 | |
140 | fn next(&mut self) -> Option<Self::Item> { |
141 | let item: &Item = self.ctx.resolve_item(self.item); |
142 | |
143 | if item.parent_id() == self.item { |
144 | None |
145 | } else { |
146 | self.item = item.parent_id(); |
147 | |
148 | extra_assert!(!self.seen.contains(&item.id())); |
149 | self.seen.insert(item.id()); |
150 | |
151 | Some(item.id()) |
152 | } |
153 | } |
154 | } |
155 | |
156 | impl<T> AsTemplateParam for T |
157 | where |
158 | T: Copy + Into<ItemId>, |
159 | { |
160 | type Extra = (); |
161 | |
162 | fn as_template_param( |
163 | &self, |
164 | ctx: &BindgenContext, |
165 | _: &(), |
166 | ) -> Option<TypeId> { |
167 | ctx.resolve_item((*self).into()).as_template_param(ctx, &()) |
168 | } |
169 | } |
170 | |
171 | impl AsTemplateParam for Item { |
172 | type Extra = (); |
173 | |
174 | fn as_template_param( |
175 | &self, |
176 | ctx: &BindgenContext, |
177 | _: &(), |
178 | ) -> Option<TypeId> { |
179 | self.kind.as_template_param(ctx, self) |
180 | } |
181 | } |
182 | |
183 | impl AsTemplateParam for ItemKind { |
184 | type Extra = Item; |
185 | |
186 | fn as_template_param( |
187 | &self, |
188 | ctx: &BindgenContext, |
189 | item: &Item, |
190 | ) -> Option<TypeId> { |
191 | match *self { |
192 | ItemKind::Type(ref ty: &Type) => ty.as_template_param(ctx, extra:item), |
193 | ItemKind::Module(..) | |
194 | ItemKind::Function(..) | |
195 | ItemKind::Var(..) => None, |
196 | } |
197 | } |
198 | } |
199 | |
200 | impl<T> ItemCanonicalName for T |
201 | where |
202 | T: Copy + Into<ItemId>, |
203 | { |
204 | fn canonical_name(&self, ctx: &BindgenContext) -> String { |
205 | debug_assert!( |
206 | ctx.in_codegen_phase(), |
207 | "You're not supposed to call this yet" |
208 | ); |
209 | ctx.resolve_item(*self).canonical_name(ctx) |
210 | } |
211 | } |
212 | |
213 | impl<T> ItemCanonicalPath for T |
214 | where |
215 | T: Copy + Into<ItemId>, |
216 | { |
217 | fn namespace_aware_canonical_path( |
218 | &self, |
219 | ctx: &BindgenContext, |
220 | ) -> Vec<String> { |
221 | debug_assert!( |
222 | ctx.in_codegen_phase(), |
223 | "You're not supposed to call this yet" |
224 | ); |
225 | ctx.resolve_item(*self).namespace_aware_canonical_path(ctx) |
226 | } |
227 | |
228 | fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> { |
229 | debug_assert!( |
230 | ctx.in_codegen_phase(), |
231 | "You're not supposed to call this yet" |
232 | ); |
233 | ctx.resolve_item(*self).canonical_path(ctx) |
234 | } |
235 | } |
236 | |
237 | impl<T> ItemAncestors for T |
238 | where |
239 | T: Copy + Into<ItemId>, |
240 | { |
241 | fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> { |
242 | ItemAncestorsIter::new(ctx, *self) |
243 | } |
244 | } |
245 | |
246 | impl ItemAncestors for Item { |
247 | fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> { |
248 | self.id().ancestors(ctx) |
249 | } |
250 | } |
251 | |
252 | impl<Id> Trace for Id |
253 | where |
254 | Id: Copy + Into<ItemId>, |
255 | { |
256 | type Extra = (); |
257 | |
258 | fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, extra: &()) |
259 | where |
260 | T: Tracer, |
261 | { |
262 | ctx.resolve_item(*self).trace(context:ctx, tracer, extra); |
263 | } |
264 | } |
265 | |
266 | impl Trace for Item { |
267 | type Extra = (); |
268 | |
269 | fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &()) |
270 | where |
271 | T: Tracer, |
272 | { |
273 | // Even if this item is blocklisted/hidden, we want to trace it. It is |
274 | // traversal iterators' consumers' responsibility to filter items as |
275 | // needed. Generally, this filtering happens in the implementation of |
276 | // `Iterator` for `allowlistedItems`. Fully tracing blocklisted items is |
277 | // necessary for things like the template parameter usage analysis to |
278 | // function correctly. |
279 | |
280 | match *self.kind() { |
281 | ItemKind::Type(ref ty) => { |
282 | // There are some types, like resolved type references, where we |
283 | // don't want to stop collecting types even though they may be |
284 | // opaque. |
285 | if ty.should_be_traced_unconditionally() || |
286 | !self.is_opaque(ctx, &()) |
287 | { |
288 | ty.trace(ctx, tracer, self); |
289 | } |
290 | } |
291 | ItemKind::Function(ref fun) => { |
292 | // Just the same way, it has not real meaning for a function to |
293 | // be opaque, so we trace across it. |
294 | tracer.visit(fun.signature().into()); |
295 | } |
296 | ItemKind::Var(ref var) => { |
297 | tracer.visit_kind(var.ty().into(), EdgeKind::VarType); |
298 | } |
299 | ItemKind::Module(_) => { |
300 | // Module -> children edges are "weak", and we do not want to |
301 | // trace them. If we did, then allowlisting wouldn't work as |
302 | // expected: everything in every module would end up |
303 | // allowlisted. |
304 | // |
305 | // TODO: make a new edge kind for module -> children edges and |
306 | // filter them during allowlisting traversals. |
307 | } |
308 | } |
309 | } |
310 | } |
311 | |
312 | impl CanDeriveDebug for Item { |
313 | fn can_derive_debug(&self, ctx: &BindgenContext) -> bool { |
314 | self.id().can_derive_debug(ctx) |
315 | } |
316 | } |
317 | |
318 | impl CanDeriveDefault for Item { |
319 | fn can_derive_default(&self, ctx: &BindgenContext) -> bool { |
320 | self.id().can_derive_default(ctx) |
321 | } |
322 | } |
323 | |
324 | impl CanDeriveCopy for Item { |
325 | fn can_derive_copy(&self, ctx: &BindgenContext) -> bool { |
326 | self.id().can_derive_copy(ctx) |
327 | } |
328 | } |
329 | |
330 | impl CanDeriveHash for Item { |
331 | fn can_derive_hash(&self, ctx: &BindgenContext) -> bool { |
332 | self.id().can_derive_hash(ctx) |
333 | } |
334 | } |
335 | |
336 | impl CanDerivePartialOrd for Item { |
337 | fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool { |
338 | self.id().can_derive_partialord(ctx) |
339 | } |
340 | } |
341 | |
342 | impl CanDerivePartialEq for Item { |
343 | fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool { |
344 | self.id().can_derive_partialeq(ctx) |
345 | } |
346 | } |
347 | |
348 | impl CanDeriveEq for Item { |
349 | fn can_derive_eq(&self, ctx: &BindgenContext) -> bool { |
350 | self.id().can_derive_eq(ctx) |
351 | } |
352 | } |
353 | |
354 | impl CanDeriveOrd for Item { |
355 | fn can_derive_ord(&self, ctx: &BindgenContext) -> bool { |
356 | self.id().can_derive_ord(ctx) |
357 | } |
358 | } |
359 | |
360 | /// An item is the base of the bindgen representation, it can be either a |
361 | /// module, a type, a function, or a variable (see `ItemKind` for more |
362 | /// information). |
363 | /// |
364 | /// Items refer to each other by `ItemId`. Every item has its parent's |
365 | /// ID. Depending on the kind of item this is, it may also refer to other items, |
366 | /// such as a compound type item referring to other types. Collectively, these |
367 | /// references form a graph. |
368 | /// |
369 | /// The entry-point to this graph is the "root module": a meta-item used to hold |
370 | /// all top-level items. |
371 | /// |
372 | /// An item may have a comment, and annotations (see the `annotations` module). |
373 | /// |
374 | /// Note that even though we parse all the types of annotations in comments, not |
375 | /// all of them apply to every item. Those rules are described in the |
376 | /// `annotations` module. |
377 | #[derive (Debug)] |
378 | pub(crate) struct Item { |
379 | /// This item's ID. |
380 | id: ItemId, |
381 | |
382 | /// The item's local ID, unique only amongst its siblings. Only used for |
383 | /// anonymous items. |
384 | /// |
385 | /// Lazily initialized in local_id(). |
386 | /// |
387 | /// Note that only structs, unions, and enums get a local type ID. In any |
388 | /// case this is an implementation detail. |
389 | local_id: LazyCell<usize>, |
390 | |
391 | /// The next local ID to use for a child or template instantiation. |
392 | next_child_local_id: Cell<usize>, |
393 | |
394 | /// A cached copy of the canonical name, as returned by `canonical_name`. |
395 | /// |
396 | /// This is a fairly used operation during codegen so this makes bindgen |
397 | /// considerably faster in those cases. |
398 | canonical_name: LazyCell<String>, |
399 | |
400 | /// The path to use for allowlisting and other name-based checks, as |
401 | /// returned by `path_for_allowlisting`, lazily constructed. |
402 | path_for_allowlisting: LazyCell<Vec<String>>, |
403 | |
404 | /// A doc comment over the item, if any. |
405 | comment: Option<String>, |
406 | /// Annotations extracted from the doc comment, or the default ones |
407 | /// otherwise. |
408 | annotations: Annotations, |
409 | /// An item's parent ID. This will most likely be a class where this item |
410 | /// was declared, or a module, etc. |
411 | /// |
412 | /// All the items have a parent, except the root module, in which case the |
413 | /// parent ID is its own ID. |
414 | parent_id: ItemId, |
415 | /// The item kind. |
416 | kind: ItemKind, |
417 | /// The source location of the item. |
418 | location: Option<clang::SourceLocation>, |
419 | } |
420 | |
421 | impl AsRef<ItemId> for Item { |
422 | fn as_ref(&self) -> &ItemId { |
423 | &self.id |
424 | } |
425 | } |
426 | |
427 | impl Item { |
428 | /// Construct a new `Item`. |
429 | pub(crate) fn new( |
430 | id: ItemId, |
431 | comment: Option<String>, |
432 | annotations: Option<Annotations>, |
433 | parent_id: ItemId, |
434 | kind: ItemKind, |
435 | location: Option<clang::SourceLocation>, |
436 | ) -> Self { |
437 | debug_assert!(id != parent_id || kind.is_module()); |
438 | Item { |
439 | id, |
440 | local_id: LazyCell::new(), |
441 | next_child_local_id: Cell::new(1), |
442 | canonical_name: LazyCell::new(), |
443 | path_for_allowlisting: LazyCell::new(), |
444 | parent_id, |
445 | comment, |
446 | annotations: annotations.unwrap_or_default(), |
447 | kind, |
448 | location, |
449 | } |
450 | } |
451 | |
452 | /// Construct a new opaque item type. |
453 | pub(crate) fn new_opaque_type( |
454 | with_id: ItemId, |
455 | ty: &clang::Type, |
456 | ctx: &mut BindgenContext, |
457 | ) -> TypeId { |
458 | let location = ty.declaration().location(); |
459 | let ty = Opaque::from_clang_ty(ty, ctx); |
460 | let kind = ItemKind::Type(ty); |
461 | let parent = ctx.root_module().into(); |
462 | ctx.add_item( |
463 | Item::new(with_id, None, None, parent, kind, Some(location)), |
464 | None, |
465 | None, |
466 | ); |
467 | with_id.as_type_id_unchecked() |
468 | } |
469 | |
470 | /// Get this `Item`'s identifier. |
471 | pub(crate) fn id(&self) -> ItemId { |
472 | self.id |
473 | } |
474 | |
475 | /// Get this `Item`'s parent's identifier. |
476 | /// |
477 | /// For the root module, the parent's ID is its own ID. |
478 | pub(crate) fn parent_id(&self) -> ItemId { |
479 | self.parent_id |
480 | } |
481 | |
482 | /// Set this item's parent ID. |
483 | /// |
484 | /// This is only used so replacements get generated in the proper module. |
485 | pub(crate) fn set_parent_for_replacement<Id: Into<ItemId>>( |
486 | &mut self, |
487 | id: Id, |
488 | ) { |
489 | self.parent_id = id.into(); |
490 | } |
491 | |
492 | /// Returns the depth this item is indented to. |
493 | /// |
494 | /// FIXME(emilio): This may need fixes for the enums within modules stuff. |
495 | pub(crate) fn codegen_depth(&self, ctx: &BindgenContext) -> usize { |
496 | if !ctx.options().enable_cxx_namespaces { |
497 | return 0; |
498 | } |
499 | |
500 | self.ancestors(ctx) |
501 | .filter(|id| { |
502 | ctx.resolve_item(*id).as_module().map_or(false, |module| { |
503 | !module.is_inline() || |
504 | ctx.options().conservative_inline_namespaces |
505 | }) |
506 | }) |
507 | .count() + |
508 | 1 |
509 | } |
510 | |
511 | /// Get this `Item`'s comment, if it has any, already preprocessed and with |
512 | /// the right indentation. |
513 | pub(crate) fn comment(&self, ctx: &BindgenContext) -> Option<String> { |
514 | if !ctx.options().generate_comments { |
515 | return None; |
516 | } |
517 | |
518 | self.comment |
519 | .as_ref() |
520 | .map(|comment| ctx.options().process_comment(comment)) |
521 | } |
522 | |
523 | /// What kind of item is this? |
524 | pub(crate) fn kind(&self) -> &ItemKind { |
525 | &self.kind |
526 | } |
527 | |
528 | /// Get a mutable reference to this item's kind. |
529 | pub(crate) fn kind_mut(&mut self) -> &mut ItemKind { |
530 | &mut self.kind |
531 | } |
532 | |
533 | /// Where in the source is this item located? |
534 | pub(crate) fn location(&self) -> Option<&clang::SourceLocation> { |
535 | self.location.as_ref() |
536 | } |
537 | |
538 | /// Get an identifier that differentiates this item from its siblings. |
539 | /// |
540 | /// This should stay relatively stable in the face of code motion outside or |
541 | /// below this item's lexical scope, meaning that this can be useful for |
542 | /// generating relatively stable identifiers within a scope. |
543 | pub(crate) fn local_id(&self, ctx: &BindgenContext) -> usize { |
544 | *self.local_id.borrow_with(|| { |
545 | let parent = ctx.resolve_item(self.parent_id); |
546 | parent.next_child_local_id() |
547 | }) |
548 | } |
549 | |
550 | /// Get an identifier that differentiates a child of this item of other |
551 | /// related items. |
552 | /// |
553 | /// This is currently used for anonymous items, and template instantiation |
554 | /// tests, in both cases in order to reduce noise when system headers are at |
555 | /// place. |
556 | pub(crate) fn next_child_local_id(&self) -> usize { |
557 | let local_id = self.next_child_local_id.get(); |
558 | self.next_child_local_id.set(local_id + 1); |
559 | local_id |
560 | } |
561 | |
562 | /// Returns whether this item is a top-level item, from the point of view of |
563 | /// bindgen. |
564 | /// |
565 | /// This point of view changes depending on whether namespaces are enabled |
566 | /// or not. That way, in the following example: |
567 | /// |
568 | /// ```c++ |
569 | /// namespace foo { |
570 | /// static int var; |
571 | /// } |
572 | /// ``` |
573 | /// |
574 | /// `var` would be a toplevel item if namespaces are disabled, but won't if |
575 | /// they aren't. |
576 | /// |
577 | /// This function is used to determine when the codegen phase should call |
578 | /// `codegen` on an item, since any item that is not top-level will be |
579 | /// generated by its parent. |
580 | pub(crate) fn is_toplevel(&self, ctx: &BindgenContext) -> bool { |
581 | // FIXME: Workaround for some types falling behind when parsing weird |
582 | // stl classes, for example. |
583 | if ctx.options().enable_cxx_namespaces && |
584 | self.kind().is_module() && |
585 | self.id() != ctx.root_module() |
586 | { |
587 | return false; |
588 | } |
589 | |
590 | let mut parent = self.parent_id; |
591 | loop { |
592 | let parent_item = match ctx.resolve_item_fallible(parent) { |
593 | Some(item) => item, |
594 | None => return false, |
595 | }; |
596 | |
597 | if parent_item.id() == ctx.root_module() { |
598 | return true; |
599 | } else if ctx.options().enable_cxx_namespaces || |
600 | !parent_item.kind().is_module() |
601 | { |
602 | return false; |
603 | } |
604 | |
605 | parent = parent_item.parent_id(); |
606 | } |
607 | } |
608 | |
609 | /// Get a reference to this item's underlying `Type`. Panic if this is some |
610 | /// other kind of item. |
611 | pub(crate) fn expect_type(&self) -> &Type { |
612 | self.kind().expect_type() |
613 | } |
614 | |
615 | /// Get a reference to this item's underlying `Type`, or `None` if this is |
616 | /// some other kind of item. |
617 | pub(crate) fn as_type(&self) -> Option<&Type> { |
618 | self.kind().as_type() |
619 | } |
620 | |
621 | /// Get a reference to this item's underlying `Function`. Panic if this is |
622 | /// some other kind of item. |
623 | pub(crate) fn expect_function(&self) -> &Function { |
624 | self.kind().expect_function() |
625 | } |
626 | |
627 | /// Is this item a module? |
628 | pub(crate) fn is_module(&self) -> bool { |
629 | matches!(self.kind, ItemKind::Module(..)) |
630 | } |
631 | |
632 | /// Get this item's annotations. |
633 | pub(crate) fn annotations(&self) -> &Annotations { |
634 | &self.annotations |
635 | } |
636 | |
637 | /// Whether this item should be blocklisted. |
638 | /// |
639 | /// This may be due to either annotations or to other kind of configuration. |
640 | pub(crate) fn is_blocklisted(&self, ctx: &BindgenContext) -> bool { |
641 | debug_assert!( |
642 | ctx.in_codegen_phase(), |
643 | "You're not supposed to call this yet" |
644 | ); |
645 | if self.annotations.hide() { |
646 | return true; |
647 | } |
648 | |
649 | if !ctx.options().blocklisted_files.is_empty() { |
650 | if let Some(location) = &self.location { |
651 | let (file, _, _, _) = location.location(); |
652 | if let Some(filename) = file.name() { |
653 | if ctx.options().blocklisted_files.matches(filename) { |
654 | return true; |
655 | } |
656 | } |
657 | } |
658 | } |
659 | |
660 | let path = self.path_for_allowlisting(ctx); |
661 | let name = path[1..].join("::" ); |
662 | ctx.options().blocklisted_items.matches(&name) || |
663 | match self.kind { |
664 | ItemKind::Type(..) => { |
665 | ctx.options().blocklisted_types.matches(&name) || |
666 | ctx.is_replaced_type(path, self.id) |
667 | } |
668 | ItemKind::Function(..) => { |
669 | ctx.options().blocklisted_functions.matches(&name) |
670 | } |
671 | ItemKind::Var(..) => { |
672 | ctx.options().blocklisted_vars.matches(&name) |
673 | } |
674 | // TODO: Add namespace blocklisting? |
675 | ItemKind::Module(..) => false, |
676 | } |
677 | } |
678 | |
679 | /// Take out item NameOptions |
680 | pub(crate) fn name<'a>( |
681 | &'a self, |
682 | ctx: &'a BindgenContext, |
683 | ) -> NameOptions<'a> { |
684 | NameOptions::new(self, ctx) |
685 | } |
686 | |
687 | /// Get the target item ID for name generation. |
688 | fn name_target(&self, ctx: &BindgenContext) -> ItemId { |
689 | let mut targets_seen = DebugOnlyItemSet::new(); |
690 | let mut item = self; |
691 | |
692 | loop { |
693 | extra_assert!(!targets_seen.contains(&item.id())); |
694 | targets_seen.insert(item.id()); |
695 | |
696 | if self.annotations().use_instead_of().is_some() { |
697 | return self.id(); |
698 | } |
699 | |
700 | match *item.kind() { |
701 | ItemKind::Type(ref ty) => match *ty.kind() { |
702 | TypeKind::ResolvedTypeRef(inner) => { |
703 | item = ctx.resolve_item(inner); |
704 | } |
705 | TypeKind::TemplateInstantiation(ref inst) => { |
706 | item = ctx.resolve_item(inst.template_definition()); |
707 | } |
708 | _ => return item.id(), |
709 | }, |
710 | _ => return item.id(), |
711 | } |
712 | } |
713 | } |
714 | |
715 | /// Create a fully disambiguated name for an item, including template |
716 | /// parameters if it is a type |
717 | pub(crate) fn full_disambiguated_name( |
718 | &self, |
719 | ctx: &BindgenContext, |
720 | ) -> String { |
721 | let mut s = String::new(); |
722 | let level = 0; |
723 | self.push_disambiguated_name(ctx, &mut s, level); |
724 | s |
725 | } |
726 | |
727 | /// Helper function for full_disambiguated_name |
728 | fn push_disambiguated_name( |
729 | &self, |
730 | ctx: &BindgenContext, |
731 | to: &mut String, |
732 | level: u8, |
733 | ) { |
734 | to.push_str(&self.canonical_name(ctx)); |
735 | if let ItemKind::Type(ref ty) = *self.kind() { |
736 | if let TypeKind::TemplateInstantiation(ref inst) = *ty.kind() { |
737 | to.push_str(&format!("_open {}_" , level)); |
738 | for arg in inst.template_arguments() { |
739 | arg.into_resolver() |
740 | .through_type_refs() |
741 | .resolve(ctx) |
742 | .push_disambiguated_name(ctx, to, level + 1); |
743 | to.push('_' ); |
744 | } |
745 | to.push_str(&format!("close {}" , level)); |
746 | } |
747 | } |
748 | } |
749 | |
750 | /// Get this function item's name, or `None` if this item is not a function. |
751 | fn func_name(&self) -> Option<&str> { |
752 | match *self.kind() { |
753 | ItemKind::Function(ref func) => Some(func.name()), |
754 | _ => None, |
755 | } |
756 | } |
757 | |
758 | /// Get the overload index for this method. If this is not a method, return |
759 | /// `None`. |
760 | fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> { |
761 | self.func_name().and_then(|func_name| { |
762 | let parent = ctx.resolve_item(self.parent_id()); |
763 | if let ItemKind::Type(ref ty) = *parent.kind() { |
764 | if let TypeKind::Comp(ref ci) = *ty.kind() { |
765 | // All the constructors have the same name, so no need to |
766 | // resolve and check. |
767 | return ci |
768 | .constructors() |
769 | .iter() |
770 | .position(|c| *c == self.id()) |
771 | .or_else(|| { |
772 | ci.methods() |
773 | .iter() |
774 | .filter(|m| { |
775 | let item = ctx.resolve_item(m.signature()); |
776 | let func = item.expect_function(); |
777 | func.name() == func_name |
778 | }) |
779 | .position(|m| m.signature() == self.id()) |
780 | }); |
781 | } |
782 | } |
783 | |
784 | None |
785 | }) |
786 | } |
787 | |
788 | /// Get this item's base name (aka non-namespaced name). |
789 | fn base_name(&self, ctx: &BindgenContext) -> String { |
790 | if let Some(path) = self.annotations().use_instead_of() { |
791 | return path.last().unwrap().clone(); |
792 | } |
793 | |
794 | match *self.kind() { |
795 | ItemKind::Var(ref var) => var.name().to_owned(), |
796 | ItemKind::Module(ref module) => { |
797 | module.name().map(ToOwned::to_owned).unwrap_or_else(|| { |
798 | format!("_bindgen_mod_ {}" , self.exposed_id(ctx)) |
799 | }) |
800 | } |
801 | ItemKind::Type(ref ty) => { |
802 | ty.sanitized_name(ctx).map(Into::into).unwrap_or_else(|| { |
803 | format!("_bindgen_ty_ {}" , self.exposed_id(ctx)) |
804 | }) |
805 | } |
806 | ItemKind::Function(ref fun) => { |
807 | let mut name = fun.name().to_owned(); |
808 | |
809 | if let Some(idx) = self.overload_index(ctx) { |
810 | if idx > 0 { |
811 | write!(&mut name, " {}" , idx).unwrap(); |
812 | } |
813 | } |
814 | |
815 | name |
816 | } |
817 | } |
818 | } |
819 | |
820 | fn is_anon(&self) -> bool { |
821 | match self.kind() { |
822 | ItemKind::Module(module) => module.name().is_none(), |
823 | ItemKind::Type(ty) => ty.name().is_none(), |
824 | ItemKind::Function(_) => false, |
825 | ItemKind::Var(_) => false, |
826 | } |
827 | } |
828 | |
829 | /// Get the canonical name without taking into account the replaces |
830 | /// annotation. |
831 | /// |
832 | /// This is the base logic used to implement hiding and replacing via |
833 | /// annotations, and also to implement proper name mangling. |
834 | /// |
835 | /// The idea is that each generated type in the same "level" (read: module |
836 | /// or namespace) has a unique canonical name. |
837 | /// |
838 | /// This name should be derived from the immutable state contained in the |
839 | /// type and the parent chain, since it should be consistent. |
840 | /// |
841 | /// If `BindgenOptions::disable_nested_struct_naming` is true then returned |
842 | /// name is the inner most non-anonymous name plus all the anonymous base names |
843 | /// that follows. |
844 | pub(crate) fn real_canonical_name( |
845 | &self, |
846 | ctx: &BindgenContext, |
847 | opt: &NameOptions, |
848 | ) -> String { |
849 | let target = ctx.resolve_item(self.name_target(ctx)); |
850 | |
851 | // Short-circuit if the target has an override, and just use that. |
852 | if let Some(path) = target.annotations.use_instead_of() { |
853 | if ctx.options().enable_cxx_namespaces { |
854 | return path.last().unwrap().clone(); |
855 | } |
856 | return path.join("_" ); |
857 | } |
858 | |
859 | let base_name = target.base_name(ctx); |
860 | |
861 | // Named template type arguments are never namespaced, and never |
862 | // mangled. |
863 | if target.is_template_param(ctx, &()) { |
864 | return base_name; |
865 | } |
866 | |
867 | // Ancestors' ID iter |
868 | let mut ids_iter = target |
869 | .parent_id() |
870 | .ancestors(ctx) |
871 | .filter(|id| *id != ctx.root_module()) |
872 | .take_while(|id| { |
873 | // Stop iterating ancestors once we reach a non-inline namespace |
874 | // when opt.within_namespaces is set. |
875 | !opt.within_namespaces || !ctx.resolve_item(*id).is_module() |
876 | }) |
877 | .filter(|id| { |
878 | if !ctx.options().conservative_inline_namespaces { |
879 | if let ItemKind::Module(ref module) = |
880 | *ctx.resolve_item(*id).kind() |
881 | { |
882 | return !module.is_inline(); |
883 | } |
884 | } |
885 | |
886 | true |
887 | }); |
888 | |
889 | let ids: Vec<_> = if ctx.options().disable_nested_struct_naming { |
890 | let mut ids = Vec::new(); |
891 | |
892 | // If target is anonymous we need find its first named ancestor. |
893 | if target.is_anon() { |
894 | for id in ids_iter.by_ref() { |
895 | ids.push(id); |
896 | |
897 | if !ctx.resolve_item(id).is_anon() { |
898 | break; |
899 | } |
900 | } |
901 | } |
902 | |
903 | ids |
904 | } else { |
905 | ids_iter.collect() |
906 | }; |
907 | |
908 | // Concatenate this item's ancestors' names together. |
909 | let mut names: Vec<_> = ids |
910 | .into_iter() |
911 | .map(|id| { |
912 | let item = ctx.resolve_item(id); |
913 | let target = ctx.resolve_item(item.name_target(ctx)); |
914 | target.base_name(ctx) |
915 | }) |
916 | .filter(|name| !name.is_empty()) |
917 | .collect(); |
918 | |
919 | names.reverse(); |
920 | |
921 | if !base_name.is_empty() { |
922 | names.push(base_name); |
923 | } |
924 | |
925 | if ctx.options().c_naming { |
926 | if let Some(prefix) = self.c_naming_prefix() { |
927 | names.insert(0, prefix.to_string()); |
928 | } |
929 | } |
930 | |
931 | let name = names.join("_" ); |
932 | |
933 | let name = if opt.user_mangled == UserMangled::Yes { |
934 | ctx.options() |
935 | .last_callback(|callbacks| callbacks.item_name(&name)) |
936 | .unwrap_or(name) |
937 | } else { |
938 | name |
939 | }; |
940 | |
941 | ctx.rust_mangle(&name).into_owned() |
942 | } |
943 | |
944 | /// The exposed ID that represents an unique ID among the siblings of a |
945 | /// given item. |
946 | pub(crate) fn exposed_id(&self, ctx: &BindgenContext) -> String { |
947 | // Only use local ids for enums, classes, structs and union types. All |
948 | // other items use their global ID. |
949 | let ty_kind = self.kind().as_type().map(|t| t.kind()); |
950 | if let Some(ty_kind) = ty_kind { |
951 | match *ty_kind { |
952 | TypeKind::Comp(..) | |
953 | TypeKind::TemplateInstantiation(..) | |
954 | TypeKind::Enum(..) => return self.local_id(ctx).to_string(), |
955 | _ => {} |
956 | } |
957 | } |
958 | |
959 | // Note that this `id_` prefix prevents (really unlikely) collisions |
960 | // between the global ID and the local ID of an item with the same |
961 | // parent. |
962 | format!("id_ {}" , self.id().as_usize()) |
963 | } |
964 | |
965 | /// Get a reference to this item's `Module`, or `None` if this is not a |
966 | /// `Module` item. |
967 | pub(crate) fn as_module(&self) -> Option<&Module> { |
968 | match self.kind { |
969 | ItemKind::Module(ref module) => Some(module), |
970 | _ => None, |
971 | } |
972 | } |
973 | |
974 | /// Get a mutable reference to this item's `Module`, or `None` if this is |
975 | /// not a `Module` item. |
976 | pub(crate) fn as_module_mut(&mut self) -> Option<&mut Module> { |
977 | match self.kind { |
978 | ItemKind::Module(ref mut module) => Some(module), |
979 | _ => None, |
980 | } |
981 | } |
982 | |
983 | /// Returns whether the item is a constified module enum |
984 | fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool { |
985 | // Do not jump through aliases, except for aliases that point to a type |
986 | // with the same name, since we dont generate coe for them. |
987 | let item = self.id.into_resolver().through_type_refs().resolve(ctx); |
988 | let type_ = match *item.kind() { |
989 | ItemKind::Type(ref type_) => type_, |
990 | _ => return false, |
991 | }; |
992 | |
993 | match *type_.kind() { |
994 | TypeKind::Enum(ref enum_) => { |
995 | enum_.computed_enum_variation(ctx, self) == |
996 | EnumVariation::ModuleConsts |
997 | } |
998 | TypeKind::Alias(inner_id) => { |
999 | // TODO(emilio): Make this "hop through type aliases that aren't |
1000 | // really generated" an option in `ItemResolver`? |
1001 | let inner_item = ctx.resolve_item(inner_id); |
1002 | let name = item.canonical_name(ctx); |
1003 | |
1004 | if inner_item.canonical_name(ctx) == name { |
1005 | inner_item.is_constified_enum_module(ctx) |
1006 | } else { |
1007 | false |
1008 | } |
1009 | } |
1010 | _ => false, |
1011 | } |
1012 | } |
1013 | |
1014 | /// Is this item of a kind that is enabled for code generation? |
1015 | pub(crate) fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool { |
1016 | let cc = &ctx.options().codegen_config; |
1017 | match *self.kind() { |
1018 | ItemKind::Module(..) => true, |
1019 | ItemKind::Var(_) => cc.vars(), |
1020 | ItemKind::Type(_) => cc.types(), |
1021 | ItemKind::Function(ref f) => match f.kind() { |
1022 | FunctionKind::Function => cc.functions(), |
1023 | FunctionKind::Method(MethodKind::Constructor) => { |
1024 | cc.constructors() |
1025 | } |
1026 | FunctionKind::Method(MethodKind::Destructor) | |
1027 | FunctionKind::Method(MethodKind::VirtualDestructor { |
1028 | .. |
1029 | }) => cc.destructors(), |
1030 | FunctionKind::Method(MethodKind::Static) | |
1031 | FunctionKind::Method(MethodKind::Normal) | |
1032 | FunctionKind::Method(MethodKind::Virtual { .. }) => { |
1033 | cc.methods() |
1034 | } |
1035 | }, |
1036 | } |
1037 | } |
1038 | |
1039 | /// Returns the path we should use for allowlisting / blocklisting, which |
1040 | /// doesn't include user-mangling. |
1041 | pub(crate) fn path_for_allowlisting( |
1042 | &self, |
1043 | ctx: &BindgenContext, |
1044 | ) -> &Vec<String> { |
1045 | self.path_for_allowlisting |
1046 | .borrow_with(|| self.compute_path(ctx, UserMangled::No)) |
1047 | } |
1048 | |
1049 | fn compute_path( |
1050 | &self, |
1051 | ctx: &BindgenContext, |
1052 | mangled: UserMangled, |
1053 | ) -> Vec<String> { |
1054 | if let Some(path) = self.annotations().use_instead_of() { |
1055 | let mut ret = |
1056 | vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()]; |
1057 | ret.extend_from_slice(path); |
1058 | return ret; |
1059 | } |
1060 | |
1061 | let target = ctx.resolve_item(self.name_target(ctx)); |
1062 | let mut path: Vec<_> = target |
1063 | .ancestors(ctx) |
1064 | .chain(iter::once(ctx.root_module().into())) |
1065 | .map(|id| ctx.resolve_item(id)) |
1066 | .filter(|item| { |
1067 | item.id() == target.id() || |
1068 | item.as_module().map_or(false, |module| { |
1069 | !module.is_inline() || |
1070 | ctx.options().conservative_inline_namespaces |
1071 | }) |
1072 | }) |
1073 | .map(|item| { |
1074 | ctx.resolve_item(item.name_target(ctx)) |
1075 | .name(ctx) |
1076 | .within_namespaces() |
1077 | .user_mangled(mangled) |
1078 | .get() |
1079 | }) |
1080 | .collect(); |
1081 | path.reverse(); |
1082 | path |
1083 | } |
1084 | |
1085 | /// Returns a prefix for the canonical name when C naming is enabled. |
1086 | fn c_naming_prefix(&self) -> Option<&str> { |
1087 | let ty = match self.kind { |
1088 | ItemKind::Type(ref ty) => ty, |
1089 | _ => return None, |
1090 | }; |
1091 | |
1092 | Some(match ty.kind() { |
1093 | TypeKind::Comp(ref ci) => match ci.kind() { |
1094 | CompKind::Struct => "struct" , |
1095 | CompKind::Union => "union" , |
1096 | }, |
1097 | TypeKind::Enum(..) => "enum" , |
1098 | _ => return None, |
1099 | }) |
1100 | } |
1101 | |
1102 | /// Whether this is a `#[must_use]` type. |
1103 | pub(crate) fn must_use(&self, ctx: &BindgenContext) -> bool { |
1104 | self.annotations().must_use_type() || ctx.must_use_type_by_name(self) |
1105 | } |
1106 | } |
1107 | |
1108 | impl<T> IsOpaque for T |
1109 | where |
1110 | T: Copy + Into<ItemId>, |
1111 | { |
1112 | type Extra = (); |
1113 | |
1114 | fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool { |
1115 | debug_assert!( |
1116 | ctx.in_codegen_phase(), |
1117 | "You're not supposed to call this yet" |
1118 | ); |
1119 | ctx.resolve_item((*self).into()).is_opaque(ctx, &()) |
1120 | } |
1121 | } |
1122 | |
1123 | impl IsOpaque for Item { |
1124 | type Extra = (); |
1125 | |
1126 | fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool { |
1127 | debug_assert!( |
1128 | ctx.in_codegen_phase(), |
1129 | "You're not supposed to call this yet" |
1130 | ); |
1131 | self.annotations.opaque() || |
1132 | self.as_type().map_or(default:false, |ty: &Type| ty.is_opaque(ctx, self)) || |
1133 | ctx.opaque_by_name(self.path_for_allowlisting(ctx)) |
1134 | } |
1135 | } |
1136 | |
1137 | impl<T> HasVtable for T |
1138 | where |
1139 | T: Copy + Into<ItemId>, |
1140 | { |
1141 | fn has_vtable(&self, ctx: &BindgenContext) -> bool { |
1142 | let id: ItemId = (*self).into(); |
1143 | id.as_type_id(ctx).map_or(default:false, |id: TypeId| { |
1144 | !matches!(ctx.lookup_has_vtable(id), HasVtableResult::No) |
1145 | }) |
1146 | } |
1147 | |
1148 | fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool { |
1149 | let id: ItemId = (*self).into(); |
1150 | id.as_type_id(ctx).map_or(default:false, |id: TypeId| { |
1151 | matches!(ctx.lookup_has_vtable(id), HasVtableResult::SelfHasVtable) |
1152 | }) |
1153 | } |
1154 | } |
1155 | |
1156 | impl HasVtable for Item { |
1157 | fn has_vtable(&self, ctx: &BindgenContext) -> bool { |
1158 | self.id().has_vtable(ctx) |
1159 | } |
1160 | |
1161 | fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool { |
1162 | self.id().has_vtable_ptr(ctx) |
1163 | } |
1164 | } |
1165 | |
1166 | impl<T> Sizedness for T |
1167 | where |
1168 | T: Copy + Into<ItemId>, |
1169 | { |
1170 | fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult { |
1171 | let id: ItemId = (*self).into(); |
1172 | id.as_type_id(ctx) |
1173 | .map_or(SizednessResult::default(), |id: TypeId| ctx.lookup_sizedness(id)) |
1174 | } |
1175 | } |
1176 | |
1177 | impl Sizedness for Item { |
1178 | fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult { |
1179 | self.id().sizedness(ctx) |
1180 | } |
1181 | } |
1182 | |
1183 | impl<T> HasTypeParamInArray for T |
1184 | where |
1185 | T: Copy + Into<ItemId>, |
1186 | { |
1187 | fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool { |
1188 | debug_assert!( |
1189 | ctx.in_codegen_phase(), |
1190 | "You're not supposed to call this yet" |
1191 | ); |
1192 | ctx.lookup_has_type_param_in_array(*self) |
1193 | } |
1194 | } |
1195 | |
1196 | impl HasTypeParamInArray for Item { |
1197 | fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool { |
1198 | debug_assert!( |
1199 | ctx.in_codegen_phase(), |
1200 | "You're not supposed to call this yet" |
1201 | ); |
1202 | ctx.lookup_has_type_param_in_array(self.id()) |
1203 | } |
1204 | } |
1205 | |
1206 | impl<T> HasFloat for T |
1207 | where |
1208 | T: Copy + Into<ItemId>, |
1209 | { |
1210 | fn has_float(&self, ctx: &BindgenContext) -> bool { |
1211 | debug_assert!( |
1212 | ctx.in_codegen_phase(), |
1213 | "You're not supposed to call this yet" |
1214 | ); |
1215 | ctx.lookup_has_float(*self) |
1216 | } |
1217 | } |
1218 | |
1219 | impl HasFloat for Item { |
1220 | fn has_float(&self, ctx: &BindgenContext) -> bool { |
1221 | debug_assert!( |
1222 | ctx.in_codegen_phase(), |
1223 | "You're not supposed to call this yet" |
1224 | ); |
1225 | ctx.lookup_has_float(self.id()) |
1226 | } |
1227 | } |
1228 | |
1229 | /// A set of items. |
1230 | pub(crate) type ItemSet = BTreeSet<ItemId>; |
1231 | |
1232 | impl DotAttributes for Item { |
1233 | fn dot_attributes<W>( |
1234 | &self, |
1235 | ctx: &BindgenContext, |
1236 | out: &mut W, |
1237 | ) -> io::Result<()> |
1238 | where |
1239 | W: io::Write, |
1240 | { |
1241 | writeln!( |
1242 | out, |
1243 | "<tr><td> {:?}</td></tr> |
1244 | <tr><td>name</td><td> {}</td></tr>" , |
1245 | self.id, |
1246 | self.name(ctx).get() |
1247 | )?; |
1248 | |
1249 | if self.is_opaque(ctx, &()) { |
1250 | writeln!(out, "<tr><td>opaque</td><td>true</td></tr>" )?; |
1251 | } |
1252 | |
1253 | self.kind.dot_attributes(ctx, out) |
1254 | } |
1255 | } |
1256 | |
1257 | impl<T> TemplateParameters for T |
1258 | where |
1259 | T: Copy + Into<ItemId>, |
1260 | { |
1261 | fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> { |
1262 | ctx.resolve_item_fallible(*self) |
1263 | .map_or(default:vec![], |item: &Item| item.self_template_params(ctx)) |
1264 | } |
1265 | } |
1266 | |
1267 | impl TemplateParameters for Item { |
1268 | fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> { |
1269 | self.kind.self_template_params(ctx) |
1270 | } |
1271 | } |
1272 | |
1273 | impl TemplateParameters for ItemKind { |
1274 | fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> { |
1275 | match *self { |
1276 | ItemKind::Type(ref ty: &Type) => ty.self_template_params(ctx), |
1277 | // If we start emitting bindings to explicitly instantiated |
1278 | // functions, then we'll need to check ItemKind::Function for |
1279 | // template params. |
1280 | ItemKind::Function(_) | ItemKind::Module(_) | ItemKind::Var(_) => { |
1281 | vec![] |
1282 | } |
1283 | } |
1284 | } |
1285 | } |
1286 | |
1287 | // An utility function to handle recursing inside nested types. |
1288 | fn visit_child( |
1289 | cur: clang::Cursor, |
1290 | id: ItemId, |
1291 | ty: &clang::Type, |
1292 | parent_id: Option<ItemId>, |
1293 | ctx: &mut BindgenContext, |
1294 | result: &mut Result<TypeId, ParseError>, |
1295 | ) -> clang_sys::CXChildVisitResult { |
1296 | use clang_sys::*; |
1297 | if result.is_ok() { |
1298 | return CXChildVisit_Break; |
1299 | } |
1300 | |
1301 | *result = Item::from_ty_with_id(id, ty, location:cur, parent_id, ctx); |
1302 | |
1303 | match *result { |
1304 | Ok(..) => CXChildVisit_Break, |
1305 | Err(ParseError::Recurse) => { |
1306 | cur.visit(|c: Cursor| visit_child(cur:c, id, ty, parent_id, ctx, result)); |
1307 | CXChildVisit_Continue |
1308 | } |
1309 | Err(ParseError::Continue) => CXChildVisit_Continue, |
1310 | } |
1311 | } |
1312 | |
1313 | impl Item { |
1314 | /// Create a builtin type. |
1315 | pub(crate) fn builtin_type( |
1316 | kind: TypeKind, |
1317 | is_const: bool, |
1318 | ctx: &mut BindgenContext, |
1319 | ) -> TypeId { |
1320 | // Feel free to add more here, I'm just lazy. |
1321 | match kind { |
1322 | TypeKind::Void | |
1323 | TypeKind::Int(..) | |
1324 | TypeKind::Pointer(..) | |
1325 | TypeKind::Float(..) => {} |
1326 | _ => panic!("Unsupported builtin type" ), |
1327 | } |
1328 | |
1329 | let ty = Type::new(None, None, kind, is_const); |
1330 | let id = ctx.next_item_id(); |
1331 | let module = ctx.root_module().into(); |
1332 | ctx.add_item( |
1333 | Item::new(id, None, None, module, ItemKind::Type(ty), None), |
1334 | None, |
1335 | None, |
1336 | ); |
1337 | id.as_type_id_unchecked() |
1338 | } |
1339 | |
1340 | /// Parse this item from the given Clang cursor. |
1341 | pub(crate) fn parse( |
1342 | cursor: clang::Cursor, |
1343 | parent_id: Option<ItemId>, |
1344 | ctx: &mut BindgenContext, |
1345 | ) -> Result<ItemId, ParseError> { |
1346 | use crate::ir::var::Var; |
1347 | use clang_sys::*; |
1348 | |
1349 | if !cursor.is_valid() { |
1350 | return Err(ParseError::Continue); |
1351 | } |
1352 | |
1353 | let comment = cursor.raw_comment(); |
1354 | let annotations = Annotations::new(&cursor); |
1355 | |
1356 | let current_module = ctx.current_module().into(); |
1357 | let relevant_parent_id = parent_id.unwrap_or(current_module); |
1358 | |
1359 | #[allow (clippy::missing_docs_in_private_items)] |
1360 | macro_rules! try_parse { |
1361 | ($what:ident) => { |
1362 | match $what::parse(cursor, ctx) { |
1363 | Ok(ParseResult::New(item, declaration)) => { |
1364 | let id = ctx.next_item_id(); |
1365 | |
1366 | ctx.add_item( |
1367 | Item::new( |
1368 | id, |
1369 | comment, |
1370 | annotations, |
1371 | relevant_parent_id, |
1372 | ItemKind::$what(item), |
1373 | Some(cursor.location()), |
1374 | ), |
1375 | declaration, |
1376 | Some(cursor), |
1377 | ); |
1378 | return Ok(id); |
1379 | } |
1380 | Ok(ParseResult::AlreadyResolved(id)) => { |
1381 | return Ok(id); |
1382 | } |
1383 | Err(ParseError::Recurse) => return Err(ParseError::Recurse), |
1384 | Err(ParseError::Continue) => {} |
1385 | } |
1386 | }; |
1387 | } |
1388 | |
1389 | try_parse!(Module); |
1390 | |
1391 | // NOTE: Is extremely important to parse functions and vars **before** |
1392 | // types. Otherwise we can parse a function declaration as a type |
1393 | // (which is legal), and lose functions to generate. |
1394 | // |
1395 | // In general, I'm not totally confident this split between |
1396 | // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but |
1397 | // I guess we can try. |
1398 | try_parse!(Function); |
1399 | try_parse!(Var); |
1400 | |
1401 | // Types are sort of special, so to avoid parsing template classes |
1402 | // twice, handle them separately. |
1403 | { |
1404 | let definition = cursor.definition(); |
1405 | let applicable_cursor = definition.unwrap_or(cursor); |
1406 | |
1407 | let relevant_parent_id = match definition { |
1408 | Some(definition) => { |
1409 | if definition != cursor { |
1410 | ctx.add_semantic_parent(definition, relevant_parent_id); |
1411 | return Ok(Item::from_ty_or_ref( |
1412 | applicable_cursor.cur_type(), |
1413 | cursor, |
1414 | parent_id, |
1415 | ctx, |
1416 | ) |
1417 | .into()); |
1418 | } |
1419 | ctx.known_semantic_parent(definition) |
1420 | .or(parent_id) |
1421 | .unwrap_or_else(|| ctx.current_module().into()) |
1422 | } |
1423 | None => relevant_parent_id, |
1424 | }; |
1425 | |
1426 | match Item::from_ty( |
1427 | &applicable_cursor.cur_type(), |
1428 | applicable_cursor, |
1429 | Some(relevant_parent_id), |
1430 | ctx, |
1431 | ) { |
1432 | Ok(ty) => return Ok(ty.into()), |
1433 | Err(ParseError::Recurse) => return Err(ParseError::Recurse), |
1434 | Err(ParseError::Continue) => {} |
1435 | } |
1436 | } |
1437 | |
1438 | match cursor.kind() { |
1439 | // On Clang 18+, extern "C" is reported accurately as a LinkageSpec. |
1440 | // Older LLVM treat it as UnexposedDecl. |
1441 | CXCursor_LinkageSpec | CXCursor_UnexposedDecl => { |
1442 | Err(ParseError::Recurse) |
1443 | } |
1444 | |
1445 | // We allowlist cursors here known to be unhandled, to prevent being |
1446 | // too noisy about this. |
1447 | CXCursor_MacroDefinition | |
1448 | CXCursor_MacroExpansion | |
1449 | CXCursor_UsingDeclaration | |
1450 | CXCursor_UsingDirective | |
1451 | CXCursor_StaticAssert | |
1452 | CXCursor_FunctionTemplate => { |
1453 | debug!( |
1454 | "Unhandled cursor kind {:?}: {:?}" , |
1455 | cursor.kind(), |
1456 | cursor |
1457 | ); |
1458 | Err(ParseError::Continue) |
1459 | } |
1460 | |
1461 | CXCursor_InclusionDirective => { |
1462 | let file = cursor.get_included_file_name(); |
1463 | match file { |
1464 | None => { |
1465 | warn!("Inclusion of a nameless file in {:?}" , cursor); |
1466 | } |
1467 | Some(included_file) => { |
1468 | for cb in &ctx.options().parse_callbacks { |
1469 | cb.include_file(&included_file); |
1470 | } |
1471 | |
1472 | ctx.add_dep(included_file.into_boxed_str()); |
1473 | } |
1474 | } |
1475 | Err(ParseError::Continue) |
1476 | } |
1477 | |
1478 | _ => { |
1479 | // ignore toplevel operator overloads |
1480 | let spelling = cursor.spelling(); |
1481 | if !spelling.starts_with("operator" ) { |
1482 | warn!( |
1483 | "Unhandled cursor kind {:?}: {:?}" , |
1484 | cursor.kind(), |
1485 | cursor |
1486 | ); |
1487 | } |
1488 | Err(ParseError::Continue) |
1489 | } |
1490 | } |
1491 | } |
1492 | |
1493 | /// Parse this item from the given Clang type, or if we haven't resolved all |
1494 | /// the other items this one depends on, an unresolved reference. |
1495 | pub(crate) fn from_ty_or_ref( |
1496 | ty: clang::Type, |
1497 | location: clang::Cursor, |
1498 | parent_id: Option<ItemId>, |
1499 | ctx: &mut BindgenContext, |
1500 | ) -> TypeId { |
1501 | let id = ctx.next_item_id(); |
1502 | Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx) |
1503 | } |
1504 | |
1505 | /// Parse a C++ type. If we find a reference to a type that has not been |
1506 | /// defined yet, use `UnresolvedTypeRef` as a placeholder. |
1507 | /// |
1508 | /// This logic is needed to avoid parsing items with the incorrect parent |
1509 | /// and it's sort of complex to explain, so I'll just point to |
1510 | /// `tests/headers/typeref.hpp` to see the kind of constructs that forced |
1511 | /// this. |
1512 | /// |
1513 | /// Typerefs are resolved once parsing is completely done, see |
1514 | /// `BindgenContext::resolve_typerefs`. |
1515 | pub(crate) fn from_ty_or_ref_with_id( |
1516 | potential_id: ItemId, |
1517 | ty: clang::Type, |
1518 | location: clang::Cursor, |
1519 | parent_id: Option<ItemId>, |
1520 | ctx: &mut BindgenContext, |
1521 | ) -> TypeId { |
1522 | debug!( |
1523 | "from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}" , |
1524 | potential_id, ty, location, parent_id |
1525 | ); |
1526 | |
1527 | if ctx.collected_typerefs() { |
1528 | debug!("refs already collected, resolving directly" ); |
1529 | return Item::from_ty_with_id( |
1530 | potential_id, |
1531 | &ty, |
1532 | location, |
1533 | parent_id, |
1534 | ctx, |
1535 | ) |
1536 | .unwrap_or_else(|_| Item::new_opaque_type(potential_id, &ty, ctx)); |
1537 | } |
1538 | |
1539 | if let Some(ty) = ctx.builtin_or_resolved_ty( |
1540 | potential_id, |
1541 | parent_id, |
1542 | &ty, |
1543 | Some(location), |
1544 | ) { |
1545 | debug!(" {:?} already resolved: {:?}" , ty, location); |
1546 | return ty; |
1547 | } |
1548 | |
1549 | debug!("New unresolved type reference: {:?}, {:?}" , ty, location); |
1550 | |
1551 | let is_const = ty.is_const(); |
1552 | let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id); |
1553 | let current_module = ctx.current_module(); |
1554 | |
1555 | ctx.add_item( |
1556 | Item::new( |
1557 | potential_id, |
1558 | None, |
1559 | None, |
1560 | parent_id.unwrap_or_else(|| current_module.into()), |
1561 | ItemKind::Type(Type::new(None, None, kind, is_const)), |
1562 | Some(location.location()), |
1563 | ), |
1564 | None, |
1565 | None, |
1566 | ); |
1567 | potential_id.as_type_id_unchecked() |
1568 | } |
1569 | |
1570 | /// Parse this item from the given Clang type. See [`Item::from_ty_with_id`]. |
1571 | pub(crate) fn from_ty( |
1572 | ty: &clang::Type, |
1573 | location: clang::Cursor, |
1574 | parent_id: Option<ItemId>, |
1575 | ctx: &mut BindgenContext, |
1576 | ) -> Result<TypeId, ParseError> { |
1577 | let id = ctx.next_item_id(); |
1578 | Item::from_ty_with_id(id, ty, location, parent_id, ctx) |
1579 | } |
1580 | |
1581 | /// This is one of the trickiest methods you'll find (probably along with |
1582 | /// some of the ones that handle templates in `BindgenContext`). |
1583 | /// |
1584 | /// This method parses a type, given the potential ID of that type (if |
1585 | /// parsing it was correct), an optional location we're scanning, which is |
1586 | /// critical some times to obtain information, an optional parent item ID, |
1587 | /// that will, if it's `None`, become the current module ID, and the |
1588 | /// context. |
1589 | pub(crate) fn from_ty_with_id( |
1590 | id: ItemId, |
1591 | ty: &clang::Type, |
1592 | location: clang::Cursor, |
1593 | parent_id: Option<ItemId>, |
1594 | ctx: &mut BindgenContext, |
1595 | ) -> Result<TypeId, ParseError> { |
1596 | use clang_sys::*; |
1597 | |
1598 | debug!( |
1599 | "Item::from_ty_with_id: {:?}\n\ |
1600 | \tty = {:?}, \n\ |
1601 | \tlocation = {:?}" , |
1602 | id, ty, location |
1603 | ); |
1604 | |
1605 | if ty.kind() == clang_sys::CXType_Unexposed || |
1606 | location.cur_type().kind() == clang_sys::CXType_Unexposed |
1607 | { |
1608 | if ty.is_associated_type() || |
1609 | location.cur_type().is_associated_type() |
1610 | { |
1611 | return Ok(Item::new_opaque_type(id, ty, ctx)); |
1612 | } |
1613 | |
1614 | if let Some(param_id) = Item::type_param(None, location, ctx) { |
1615 | return Ok(ctx.build_ty_wrapper(id, param_id, None, ty)); |
1616 | } |
1617 | } |
1618 | |
1619 | // Treat all types that are declared inside functions as opaque. The Rust binding |
1620 | // won't be able to do anything with them anyway. |
1621 | // |
1622 | // (If we don't do this check here, we can have subtle logic bugs because we generally |
1623 | // ignore function bodies. See issue #2036.) |
1624 | if let Some(ref parent) = ty.declaration().fallible_semantic_parent() { |
1625 | if FunctionKind::from_cursor(parent).is_some() { |
1626 | debug!("Skipping type declared inside function: {:?}" , ty); |
1627 | return Ok(Item::new_opaque_type(id, ty, ctx)); |
1628 | } |
1629 | } |
1630 | |
1631 | let decl = { |
1632 | let canonical_def = ty.canonical_type().declaration().definition(); |
1633 | canonical_def.unwrap_or_else(|| ty.declaration()) |
1634 | }; |
1635 | |
1636 | let comment = location |
1637 | .raw_comment() |
1638 | .or_else(|| decl.raw_comment()) |
1639 | .or_else(|| location.raw_comment()); |
1640 | |
1641 | let annotations = |
1642 | Annotations::new(&decl).or_else(|| Annotations::new(&location)); |
1643 | |
1644 | if let Some(ref annotations) = annotations { |
1645 | if let Some(replaced) = annotations.use_instead_of() { |
1646 | ctx.replace(replaced, id); |
1647 | } |
1648 | } |
1649 | |
1650 | if let Some(ty) = |
1651 | ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location)) |
1652 | { |
1653 | return Ok(ty); |
1654 | } |
1655 | |
1656 | // First, check we're not recursing. |
1657 | let mut valid_decl = decl.kind() != CXCursor_NoDeclFound; |
1658 | let declaration_to_look_for = if valid_decl { |
1659 | decl.canonical() |
1660 | } else if location.kind() == CXCursor_ClassTemplate { |
1661 | valid_decl = true; |
1662 | location |
1663 | } else { |
1664 | decl |
1665 | }; |
1666 | |
1667 | if valid_decl { |
1668 | if let Some(partial) = ctx |
1669 | .currently_parsed_types() |
1670 | .iter() |
1671 | .find(|ty| *ty.decl() == declaration_to_look_for) |
1672 | { |
1673 | debug!("Avoiding recursion parsing type: {:?}" , ty); |
1674 | // Unchecked because we haven't finished this type yet. |
1675 | return Ok(partial.id().as_type_id_unchecked()); |
1676 | } |
1677 | } |
1678 | |
1679 | let current_module = ctx.current_module().into(); |
1680 | let partial_ty = PartialType::new(declaration_to_look_for, id); |
1681 | if valid_decl { |
1682 | ctx.begin_parsing(partial_ty); |
1683 | } |
1684 | |
1685 | let result = Type::from_clang_ty(id, ty, location, parent_id, ctx); |
1686 | let relevant_parent_id = parent_id.unwrap_or(current_module); |
1687 | let ret = match result { |
1688 | Ok(ParseResult::AlreadyResolved(ty)) => { |
1689 | Ok(ty.as_type_id_unchecked()) |
1690 | } |
1691 | Ok(ParseResult::New(item, declaration)) => { |
1692 | ctx.add_item( |
1693 | Item::new( |
1694 | id, |
1695 | comment, |
1696 | annotations, |
1697 | relevant_parent_id, |
1698 | ItemKind::Type(item), |
1699 | Some(location.location()), |
1700 | ), |
1701 | declaration, |
1702 | Some(location), |
1703 | ); |
1704 | Ok(id.as_type_id_unchecked()) |
1705 | } |
1706 | Err(ParseError::Continue) => Err(ParseError::Continue), |
1707 | Err(ParseError::Recurse) => { |
1708 | debug!("Item::from_ty recursing in the ast" ); |
1709 | let mut result = Err(ParseError::Recurse); |
1710 | |
1711 | // Need to pop here, otherwise we'll get stuck. |
1712 | // |
1713 | // TODO: Find a nicer interface, really. Also, the |
1714 | // declaration_to_look_for suspiciously shares a lot of |
1715 | // logic with ir::context, so we should refactor that. |
1716 | if valid_decl { |
1717 | let finished = ctx.finish_parsing(); |
1718 | assert_eq!(*finished.decl(), declaration_to_look_for); |
1719 | } |
1720 | |
1721 | location.visit(|cur| { |
1722 | visit_child(cur, id, ty, parent_id, ctx, &mut result) |
1723 | }); |
1724 | |
1725 | if valid_decl { |
1726 | let partial_ty = |
1727 | PartialType::new(declaration_to_look_for, id); |
1728 | ctx.begin_parsing(partial_ty); |
1729 | } |
1730 | |
1731 | // If we have recursed into the AST all we know, and we still |
1732 | // haven't found what we've got, let's just try and make a named |
1733 | // type. |
1734 | // |
1735 | // This is what happens with some template members, for example. |
1736 | if let Err(ParseError::Recurse) = result { |
1737 | warn!( |
1738 | "Unknown type, assuming named template type: \ |
1739 | id = {:?}; spelling = {}" , |
1740 | id, |
1741 | ty.spelling() |
1742 | ); |
1743 | Item::type_param(Some(id), location, ctx) |
1744 | .map(Ok) |
1745 | .unwrap_or(Err(ParseError::Recurse)) |
1746 | } else { |
1747 | result |
1748 | } |
1749 | } |
1750 | }; |
1751 | |
1752 | if valid_decl { |
1753 | let partial_ty = ctx.finish_parsing(); |
1754 | assert_eq!(*partial_ty.decl(), declaration_to_look_for); |
1755 | } |
1756 | |
1757 | ret |
1758 | } |
1759 | |
1760 | /// A named type is a template parameter, e.g., the `T` in `Foo<T>`. They're always local so |
1761 | /// it's the only exception when there's no declaration for a type. |
1762 | pub(crate) fn type_param( |
1763 | with_id: Option<ItemId>, |
1764 | location: clang::Cursor, |
1765 | ctx: &mut BindgenContext, |
1766 | ) -> Option<TypeId> { |
1767 | let ty = location.cur_type(); |
1768 | |
1769 | debug!( |
1770 | "Item::type_param: \n\ |
1771 | \twith_id = {:?}, \n\ |
1772 | \tty = {} {:?}, \n\ |
1773 | \tlocation: {:?}" , |
1774 | with_id, |
1775 | ty.spelling(), |
1776 | ty, |
1777 | location |
1778 | ); |
1779 | |
1780 | if ty.kind() != clang_sys::CXType_Unexposed { |
1781 | // If the given cursor's type's kind is not Unexposed, then we |
1782 | // aren't looking at a template parameter. This check may need to be |
1783 | // updated in the future if they start properly exposing template |
1784 | // type parameters. |
1785 | return None; |
1786 | } |
1787 | |
1788 | let ty_spelling = ty.spelling(); |
1789 | |
1790 | // Clang does not expose any information about template type parameters |
1791 | // via their clang::Type, nor does it give us their canonical cursors |
1792 | // the straightforward way. However, there are three situations from |
1793 | // which we can find the definition of the template type parameter, if |
1794 | // the cursor is indeed looking at some kind of a template type |
1795 | // parameter or use of one: |
1796 | // |
1797 | // 1. The cursor is pointing at the template type parameter's |
1798 | // definition. This is the trivial case. |
1799 | // |
1800 | // (kind = TemplateTypeParameter, ...) |
1801 | // |
1802 | // 2. The cursor is pointing at a TypeRef whose referenced() cursor is |
1803 | // situation (1). |
1804 | // |
1805 | // (kind = TypeRef, |
1806 | // referenced = (kind = TemplateTypeParameter, ...), |
1807 | // ...) |
1808 | // |
1809 | // 3. The cursor is pointing at some use of a template type parameter |
1810 | // (for example, in a FieldDecl), and this cursor has a child cursor |
1811 | // whose spelling is the same as the parent's type's spelling, and whose |
1812 | // kind is a TypeRef of the situation (2) variety. |
1813 | // |
1814 | // (kind = FieldDecl, |
1815 | // type = (kind = Unexposed, |
1816 | // spelling = "T", |
1817 | // ...), |
1818 | // children = |
1819 | // (kind = TypeRef, |
1820 | // spelling = "T", |
1821 | // referenced = (kind = TemplateTypeParameter, |
1822 | // spelling = "T", |
1823 | // ...), |
1824 | // ...) |
1825 | // ...) |
1826 | // |
1827 | // TODO: The alternative to this hacky pattern matching would be to |
1828 | // maintain proper scopes of template parameters while parsing and use |
1829 | // de Brujin indices to access template parameters, which clang exposes |
1830 | // in the cursor's type's canonical type's spelling: |
1831 | // "type-parameter-x-y". That is probably a better approach long-term, |
1832 | // but maintaining these scopes properly would require more changes to |
1833 | // the whole libclang -> IR parsing code. |
1834 | |
1835 | fn is_template_with_spelling( |
1836 | refd: &clang::Cursor, |
1837 | spelling: &str, |
1838 | ) -> bool { |
1839 | lazy_static! { |
1840 | static ref ANON_TYPE_PARAM_RE: regex::Regex = |
1841 | regex::Regex::new(r"^type\-parameter\-\d+\-\d+$" ).unwrap(); |
1842 | } |
1843 | |
1844 | if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter { |
1845 | return false; |
1846 | } |
1847 | |
1848 | let refd_spelling = refd.spelling(); |
1849 | refd_spelling == spelling || |
1850 | // Allow for anonymous template parameters. |
1851 | (refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref())) |
1852 | } |
1853 | |
1854 | let definition = if is_template_with_spelling(&location, &ty_spelling) { |
1855 | // Situation (1) |
1856 | location |
1857 | } else if location.kind() == clang_sys::CXCursor_TypeRef { |
1858 | // Situation (2) |
1859 | match location.referenced() { |
1860 | Some(refd) |
1861 | if is_template_with_spelling(&refd, &ty_spelling) => |
1862 | { |
1863 | refd |
1864 | } |
1865 | _ => return None, |
1866 | } |
1867 | } else { |
1868 | // Situation (3) |
1869 | let mut definition = None; |
1870 | |
1871 | location.visit(|child| { |
1872 | let child_ty = child.cur_type(); |
1873 | if child_ty.kind() == clang_sys::CXCursor_TypeRef && |
1874 | child_ty.spelling() == ty_spelling |
1875 | { |
1876 | match child.referenced() { |
1877 | Some(refd) |
1878 | if is_template_with_spelling( |
1879 | &refd, |
1880 | &ty_spelling, |
1881 | ) => |
1882 | { |
1883 | definition = Some(refd); |
1884 | return clang_sys::CXChildVisit_Break; |
1885 | } |
1886 | _ => {} |
1887 | } |
1888 | } |
1889 | |
1890 | clang_sys::CXChildVisit_Continue |
1891 | }); |
1892 | |
1893 | definition? |
1894 | }; |
1895 | assert!(is_template_with_spelling(&definition, &ty_spelling)); |
1896 | |
1897 | // Named types are always parented to the root module. They are never |
1898 | // referenced with namespace prefixes, and they can't inherit anything |
1899 | // from their parent either, so it is simplest to just hang them off |
1900 | // something we know will always exist. |
1901 | let parent = ctx.root_module().into(); |
1902 | |
1903 | if let Some(id) = ctx.get_type_param(&definition) { |
1904 | if let Some(with_id) = with_id { |
1905 | return Some(ctx.build_ty_wrapper( |
1906 | with_id, |
1907 | id, |
1908 | Some(parent), |
1909 | &ty, |
1910 | )); |
1911 | } else { |
1912 | return Some(id); |
1913 | } |
1914 | } |
1915 | |
1916 | // See tests/headers/const_tparam.hpp and |
1917 | // tests/headers/variadic_tname.hpp. |
1918 | let name = ty_spelling.replace("const " , "" ).replace('.' , "" ); |
1919 | |
1920 | let id = with_id.unwrap_or_else(|| ctx.next_item_id()); |
1921 | let item = Item::new( |
1922 | id, |
1923 | None, |
1924 | None, |
1925 | parent, |
1926 | ItemKind::Type(Type::named(name)), |
1927 | Some(location.location()), |
1928 | ); |
1929 | ctx.add_type_param(item, definition); |
1930 | Some(id.as_type_id_unchecked()) |
1931 | } |
1932 | } |
1933 | |
1934 | impl ItemCanonicalName for Item { |
1935 | fn canonical_name(&self, ctx: &BindgenContext) -> String { |
1936 | debug_assert!( |
1937 | ctx.in_codegen_phase(), |
1938 | "You're not supposed to call this yet" |
1939 | ); |
1940 | self.canonical_name |
1941 | .borrow_with(|| { |
1942 | let in_namespace: bool = ctx.options().enable_cxx_namespaces || |
1943 | ctx.options().disable_name_namespacing; |
1944 | |
1945 | if in_namespace { |
1946 | self.name(ctx).within_namespaces().get() |
1947 | } else { |
1948 | self.name(ctx).get() |
1949 | } |
1950 | }) |
1951 | .clone() |
1952 | } |
1953 | } |
1954 | |
1955 | impl ItemCanonicalPath for Item { |
1956 | fn namespace_aware_canonical_path( |
1957 | &self, |
1958 | ctx: &BindgenContext, |
1959 | ) -> Vec<String> { |
1960 | let mut path = self.canonical_path(ctx); |
1961 | |
1962 | // ASSUMPTION: (disable_name_namespacing && cxx_namespaces) |
1963 | // is equivalent to |
1964 | // disable_name_namespacing |
1965 | if ctx.options().disable_name_namespacing { |
1966 | // Only keep the last item in path |
1967 | let split_idx = path.len() - 1; |
1968 | path = path.split_off(split_idx); |
1969 | } else if !ctx.options().enable_cxx_namespaces { |
1970 | // Ignore first item "root" |
1971 | path = vec![path[1..].join("_" )]; |
1972 | } |
1973 | |
1974 | if self.is_constified_enum_module(ctx) { |
1975 | path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into()); |
1976 | } |
1977 | |
1978 | path |
1979 | } |
1980 | |
1981 | fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> { |
1982 | self.compute_path(ctx, UserMangled::Yes) |
1983 | } |
1984 | } |
1985 | |
1986 | /// Whether to use the user-mangled name (mangled by the `item_name` callback or |
1987 | /// not. |
1988 | /// |
1989 | /// Most of the callers probably want just yes, but the ones dealing with |
1990 | /// allowlisting and blocklisting don't. |
1991 | #[derive (Copy, Clone, Debug, PartialEq)] |
1992 | enum UserMangled { |
1993 | No, |
1994 | Yes, |
1995 | } |
1996 | |
1997 | /// Builder struct for naming variations, which hold inside different |
1998 | /// flags for naming options. |
1999 | #[derive (Debug)] |
2000 | pub(crate) struct NameOptions<'a> { |
2001 | item: &'a Item, |
2002 | ctx: &'a BindgenContext, |
2003 | within_namespaces: bool, |
2004 | user_mangled: UserMangled, |
2005 | } |
2006 | |
2007 | impl<'a> NameOptions<'a> { |
2008 | /// Construct a new `NameOptions` |
2009 | pub(crate) fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self { |
2010 | NameOptions { |
2011 | item, |
2012 | ctx, |
2013 | within_namespaces: false, |
2014 | user_mangled: UserMangled::Yes, |
2015 | } |
2016 | } |
2017 | |
2018 | /// Construct the name without the item's containing C++ namespaces mangled |
2019 | /// into it. In other words, the item's name within the item's namespace. |
2020 | pub(crate) fn within_namespaces(&mut self) -> &mut Self { |
2021 | self.within_namespaces = true; |
2022 | self |
2023 | } |
2024 | |
2025 | fn user_mangled(&mut self, user_mangled: UserMangled) -> &mut Self { |
2026 | self.user_mangled = user_mangled; |
2027 | self |
2028 | } |
2029 | |
2030 | /// Construct a name `String` |
2031 | pub(crate) fn get(&self) -> String { |
2032 | self.item.real_canonical_name(self.ctx, self) |
2033 | } |
2034 | } |
2035 | |