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