Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions bindgen-tests/tests/headers/3119_overlapping_alias_comment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// bindgen-flags: --no-layout-tests

/**
* This is a forward declared struct alias with overlapping names
* and documentation.
*/
typedef struct Struct Struct;
39 changes: 38 additions & 1 deletion bindgen/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1848,7 +1848,10 @@ If you encounter an error missing from this list, please file an issue or a PR!"
ty: &clang::Type,
location: Option<Cursor>,
) -> Option<TypeId> {
use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef};
use clang_sys::{
CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef,
CXCursor_TypedefDecl,
};
debug!("builtin_or_resolved_ty: {ty:?}, {location:?}, {with_id:?}, {parent_id:?}");

if let Some(decl) = ty.canonical_declaration(location.as_ref()) {
Expand All @@ -1864,6 +1867,18 @@ If you encounter an error missing from this list, please file an issue or a PR!"
// * we have already parsed and resolved this type, and
// there's nothing left to do.
if let Some(location) = location {
// When a hidden `typedef struct Foo Foo;` carries docs, the
// alias is not emitted in codegen and those docs would
// otherwise be lost. Attach the docs to the already-resolved
// target type here.
if location.kind() == CXCursor_TypedefDecl {
self.inherit_typedef_comment(
id,
*decl.cursor(),
location,
);
}

if decl.cursor().is_template_like() &&
*ty != decl.cursor().cur_type()
{
Expand Down Expand Up @@ -1899,6 +1914,28 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.build_builtin_ty(ty)
}

fn inherit_typedef_comment(
&mut self,
resolved_type: TypeId,
decl: Cursor,
typedef_cursor: Cursor,
) {
let Some(comment) = typedef_cursor.raw_comment() else {
return;
};

// Only inherit docs for hidden overlapping aliases, e.g.
// `typedef struct Foo Foo;`.
if typedef_cursor.spelling() != decl.spelling() {
return;
}

let item_id: ItemId = resolved_type.into();
if let Some(item) = self.items[item_id.0].as_mut() {
item.set_comment_if_none(comment);
}
}

/// Make a new item that is a resolved type reference to the `wrapped_id`.
///
/// This is unfortunately a lot of bloat, but is needed to properly track
Expand Down
7 changes: 7 additions & 0 deletions bindgen/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,13 @@ impl Item {
.map(|comment| ctx.options().process_comment(comment))
}

/// Set this item's raw comment if it does not already have one.
pub(crate) fn set_comment_if_none(&mut self, comment: String) {
if self.comment.is_none() {
self.comment = Some(comment);
}
}

/// What kind of item is this?
pub(crate) fn kind(&self) -> &ItemKind {
&self.kind
Expand Down