Skip to content

Commit

Permalink
Squashed commits. Added functionality to resolve fully-qualified trai…
Browse files Browse the repository at this point in the history
…t associated types in cbindgen

Parsed associated types to map

Parsed associated type on function signature. Replaced assoc type with concrete type

Fixed unwraps. Changed storage of AssocTypeId in function

Fixed unwraps in Parse::load_syn_impl()

Moved AssocTypeId into GenericPath (Type::Path(GenericPath))

Minor changes

Moved assoc type translation to Library. Added for consts and structs

Added 1 test for assoc_types

Automatic output from tests

Minor fixes

Fixed things from feedback

Added recursive associated type replacements. Added test for array

Added test for nested associated types in func ptr and raw ptr

Added assoc type replacement for all types in Library. Added tests for each

Minor fixes + cargo fmt

WIP: Resolving nested associated types

Added GenericParam parsing. Fixed nested associated types.

Added fn for generic_params. Added OpaqueItem processing in library

Added resolve_assoc for Literal. Moved resolve_assoc to individual ir types

Moved resolve_assoc_types to Item trait. Added type alias for AssocTypeResolver

Add docs for no-export
  • Loading branch information
orangeng committed Dec 7, 2023
1 parent 703b53c commit c15a902
Show file tree
Hide file tree
Showing 32 changed files with 1,334 additions and 29 deletions.
17 changes: 17 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,23 @@ pub mod my_interesting_mod;
pub mod my_uninteresting_mod; // This won't be scanned by cbindgen.
```

### No export annotation

cbindgen will usually emit all items it finds, as instructed by the parse and export config sections. This annotation will make cbindgen skip this item from the output, while still being aware of it. This is useful for a) suppressing "Can't find" errors and b) emitting `struct my_struct` for types in a different header (rather than a bare `my_struct`).

There is no equivalent config for this annotation - by comparison, the export exclude config will cause cbindgen to not be aware of the item at all.

Note that cbindgen will still traverse `no-export` structs that are `repr(C)` to emit types present in the fields. You will need to manually exclude those types in your config if desired.

```
/// cbindgen:no-export
#[repr(C)]
pub struct Foo { .. }; // This won't be emitted by cbindgen in the header
#[repr(C)]
fn bar() -> Foo { .. } // Will be emitted as `struct foo bar();`
```

### Struct Annotations

* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output struct. These names will be output verbatim, and are not eligible for renaming.
Expand Down
15 changes: 15 additions & 0 deletions src/bindgen/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,20 @@ impl Builder {

result.source_files.extend_from_slice(self.srcs.as_slice());

let assoc_types = result
.assoc_types
.into_iter()
.filter_map(
|(id, (ty_, count))| {
if count == 0 {
Some((id, ty_))
} else {
None
}
},
)
.collect();

Library::new(
self.config,
result.constants,
Expand All @@ -405,6 +419,7 @@ impl Builder {
result.typedefs,
result.functions,
result.source_files,
assoc_types,
)
.generate()
}
Expand Down
34 changes: 32 additions & 2 deletions src/bindgen/ir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::bindgen::config::{Config, Language};
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
use crate::bindgen::dependencies::Dependencies;
use crate::bindgen::ir::{
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
Struct, ToCondition, Type,
AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Documentation, GenericParams, Item,
ItemContainer, Path, Struct, ToCondition, Type,
};
use crate::bindgen::library::Library;
use crate::bindgen::writer::{Source, SourceWriter};
Expand Down Expand Up @@ -237,6 +237,31 @@ impl Literal {
});
uses_only_primitive_types
}

pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
match self {
Literal::PostfixUnaryOp { value, .. } => {
value.resolve_assoc_types(resolver);
}
Literal::BinOp { left, right, .. } => {
left.resolve_assoc_types(resolver);
right.resolve_assoc_types(resolver);
}
Literal::FieldAccess { base, .. } => {
base.resolve_assoc_types(resolver);
}
Literal::Struct { fields, .. } => {
for (_, literal) in fields {
literal.resolve_assoc_types(resolver);
}
}
Literal::Cast { ty, value } => {
value.resolve_assoc_types(resolver);
ty.resolve_assoc_types(resolver);
}
_ => {}
}
}
}

impl Literal {
Expand Down Expand Up @@ -689,6 +714,11 @@ impl Item for Constant {
fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) {
self.ty.resolve_declaration_types(resolver);
}

fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
self.ty.resolve_assoc_types(resolver);
self.value.resolve_assoc_types(resolver);
}
}

impl Constant {
Expand Down
19 changes: 16 additions & 3 deletions src/bindgen/ir/enumeration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use crate::bindgen::config::{Config, Language};
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
use crate::bindgen::dependencies::Dependencies;
use crate::bindgen::ir::{
AnnotationSet, AnnotationValue, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, Field,
GenericArgument, GenericParams, GenericPath, Item, ItemContainer, Literal, Path, Repr,
ReprStyle, Struct, ToCondition, Type,
AnnotationSet, AnnotationValue, AssocTypeResolver, Cfg, ConditionWrite, DeprecatedNoteKind,
Documentation, Field, GenericArgument, GenericParams, GenericPath, Item, ItemContainer,
Literal, Path, Repr, ReprStyle, Struct, ToCondition, Type,
};
use crate::bindgen::library::Library;
use crate::bindgen::mangle;
Expand Down Expand Up @@ -652,6 +652,19 @@ impl Item for Enum {
variant.add_dependencies(library, out);
}
}

fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
for variant in self.variants.iter_mut() {
if let Some(literal) = variant.discriminant.as_mut() {
literal.resolve_assoc_types(resolver);
}
if let VariantBody::Body { body, .. } = &mut variant.body {
body.resolve_assoc_types(resolver);
}
}

self.generic_params.resolve_assoc_types(resolver);
}
}

impl Source for Enum {
Expand Down
6 changes: 5 additions & 1 deletion src/bindgen/ir/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use syn::ext::IdentExt;
use crate::bindgen::cdecl;
use crate::bindgen::config::{Config, Language};
use crate::bindgen::ir::{AnnotationSet, Cfg, ConditionWrite};
use crate::bindgen::ir::{Documentation, Path, ToCondition, Type};
use crate::bindgen::ir::{AssocTypeResolver, Documentation, Path, ToCondition, Type};
use crate::bindgen::writer::{Source, SourceWriter};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -47,6 +47,10 @@ impl Field {
None
})
}

pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
self.ty.resolve_assoc_types(resolver);
}
}

impl Source for Field {
Expand Down
12 changes: 10 additions & 2 deletions src/bindgen/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::bindgen::config::{Config, Language, Layout};
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
use crate::bindgen::dependencies::Dependencies;
use crate::bindgen::ir::{
AnnotationSet, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation, GenericPath, Path,
ToCondition, Type,
AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, DeprecatedNoteKind, Documentation,
GenericPath, Path, ToCondition, Type,
};
use crate::bindgen::library::Library;
use crate::bindgen::monomorph::Monomorphs;
Expand Down Expand Up @@ -218,6 +218,14 @@ impl Function {
}
}
}

pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
self.ret.resolve_assoc_types(resolver);

for arg in self.args.iter_mut() {
arg.ty.resolve_assoc_types(resolver);
}
}
}

impl Source for Function {
Expand Down
64 changes: 61 additions & 3 deletions src/bindgen/ir/generic_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,45 @@ use syn::ext::IdentExt;
use crate::bindgen::cdecl;
use crate::bindgen::config::{Config, Language};
use crate::bindgen::declarationtyperesolver::{DeclarationType, DeclarationTypeResolver};
use crate::bindgen::ir::{ConstExpr, Path, Type};
use crate::bindgen::ir::{AssocTypeResolver, ConstExpr, Path, Type};
use crate::bindgen::utilities::IterHelpers;
use crate::bindgen::writer::{Source, SourceWriter};

// Struct that serves as key for resolving associated types
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct AssocTypeId {
pub ty: Box<Type>,
pub trait_: Path,
pub ident: Path,
}

impl AssocTypeId {
pub fn load(path: &syn::Path, qself: &Option<syn::QSelf>) -> Result<Self, String> {
let self_type = &qself
.as_ref()
.ok_or(String::from("Type is not fully-qualified."))?
.ty;

let ir_type_opt = Type::load(&self_type)?;
let ir_type = ir_type_opt.ok_or(String::from("Valid but empty type"))?;

let path_len = path.segments.len();
// Theoretically not possible if qself is present
if path_len < 2 {
return Err(String::from("Trait not found in type"));
}

let ident = path.segments.last().unwrap().ident.to_string();
let trait_ident = path.segments[path_len - 2].ident.to_string();

Ok(AssocTypeId {
ty: Box::new(ir_type),
trait_: Path::new(trait_ident),
ident: Path::new(ident),
})
}
}

#[derive(Debug, Clone)]
pub enum GenericParamType {
Type,
Expand Down Expand Up @@ -57,6 +92,10 @@ impl GenericParam {
pub fn name(&self) -> &Path {
&self.name
}

pub fn ty(&mut self) -> &mut GenericParamType {
&mut self.ty
}
}

#[derive(Default, Debug, Clone)]
Expand Down Expand Up @@ -129,6 +168,14 @@ impl GenericParams {
pub fn write_with_default<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.write_internal(config, out, true);
}

pub fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
for generic_param in self.0.iter_mut() {
if let GenericParamType::Const(ty_) = generic_param.ty() {
ty_.resolve_assoc_types(resolver);
}
}
}
}

impl Deref for GenericParams {
Expand Down Expand Up @@ -200,6 +247,7 @@ pub struct GenericPath {
export_name: String,
generics: Vec<GenericArgument>,
ctype: Option<DeclarationType>,
assoc: Option<AssocTypeId>,
}

impl GenericPath {
Expand All @@ -210,6 +258,7 @@ impl GenericPath {
export_name,
generics,
ctype: None,
assoc: None,
}
}

Expand Down Expand Up @@ -248,6 +297,10 @@ impl GenericPath {
&self.export_name
}

pub fn assoc(&self) -> Option<&AssocTypeId> {
self.assoc.as_ref()
}

pub fn is_single_identifier(&self) -> bool {
self.generics.is_empty()
}
Expand All @@ -265,7 +318,7 @@ impl GenericPath {
self.ctype = resolver.type_for(&self.path);
}

pub fn load(path: &syn::Path) -> Result<Self, String> {
pub fn load(path: &syn::Path, qself: &Option<syn::QSelf>) -> Result<Self, String> {
assert!(
!path.segments.is_empty(),
"{:?} doesn't have any segments",
Expand All @@ -274,6 +327,8 @@ impl GenericPath {
let last_segment = path.segments.last().unwrap();
let name = last_segment.ident.unraw().to_string();

let assoc = AssocTypeId::load(path, qself).ok();

let path = Path::new(name);
let phantom_data_path = Path::new("PhantomData");
if path == phantom_data_path {
Expand All @@ -298,6 +353,9 @@ impl GenericPath {
_ => Vec::new(),
};

Ok(Self::new(path, generics))
let mut ret = Self::new(path, generics);
ret.assoc = assoc;

Ok(ret)
}
}
8 changes: 7 additions & 1 deletion src/bindgen/ir/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use crate::bindgen::cdecl;
use crate::bindgen::config::Config;
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
use crate::bindgen::dependencies::Dependencies;
use crate::bindgen::ir::{AnnotationSet, Cfg, Documentation, Item, ItemContainer, Path, Type};
use crate::bindgen::ir::{
AnnotationSet, AssocTypeResolver, Cfg, Documentation, Item, ItemContainer, Path, Type,
};
use crate::bindgen::library::Library;
use crate::bindgen::writer::{Source, SourceWriter};

Expand Down Expand Up @@ -106,6 +108,10 @@ impl Item for Static {
fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
self.ty.add_dependencies(library, out);
}

fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
self.ty.resolve_assoc_types(resolver);
}
}

impl Source for Static {
Expand Down
5 changes: 3 additions & 2 deletions src/bindgen/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use crate::bindgen::config::Config;
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
use crate::bindgen::dependencies::Dependencies;
use crate::bindgen::ir::{
AnnotationSet, Cfg, Constant, Enum, GenericArgument, OpaqueItem, Path, Static, Struct, Typedef,
Union,
AnnotationSet, AssocTypeResolver, Cfg, Constant, Enum, GenericArgument, OpaqueItem, Path,
Static, Struct, Typedef, Union,
};
use crate::bindgen::library::Library;
use crate::bindgen::monomorph::Monomorphs;
Expand Down Expand Up @@ -46,6 +46,7 @@ pub trait Item {
) {
unreachable!("Cannot instantiate {} as a generic.", self.name())
}
fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver);
}

#[derive(Debug, Clone)]
Expand Down
8 changes: 6 additions & 2 deletions src/bindgen/ir/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::bindgen::config::{Config, Language};
use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
use crate::bindgen::dependencies::Dependencies;
use crate::bindgen::ir::{
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericArgument, GenericParams, Item,
ItemContainer, Path, ToCondition,
AnnotationSet, AssocTypeResolver, Cfg, ConditionWrite, Documentation, GenericArgument,
GenericParams, Item, ItemContainer, Path, ToCondition,
};
use crate::bindgen::library::Library;
use crate::bindgen::mangle;
Expand Down Expand Up @@ -135,6 +135,10 @@ impl Item for OpaqueItem {

out.insert_opaque(self, monomorph, generic_values.to_owned());
}

fn resolve_assoc_types(&mut self, resolver: &AssocTypeResolver) {
self.generic_params.resolve_assoc_types(resolver);
}
}

impl Source for OpaqueItem {
Expand Down
Loading

0 comments on commit c15a902

Please sign in to comment.