Skip to content

Commit

Permalink
Typedefs to references work
Browse files Browse the repository at this point in the history
  • Loading branch information
adetaylor committed Jun 28, 2023
1 parent e80dc35 commit 836b139
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 30 deletions.
26 changes: 22 additions & 4 deletions engine/src/conversion/analysis/tdef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ use crate::{
types::QualifiedName,
};

use super::{type_converter::TypedefTargetType, PointerTreatment};

#[derive(std::fmt::Debug)]
pub(crate) struct TypedefAnalysis {
pub(crate) kind: TypedefKind,
pub(crate) target: TypedefTargetType,
pub(crate) deps: HashSet<QualifiedName>,
}

Expand Down Expand Up @@ -64,12 +67,16 @@ pub(crate) fn convert_typedef_targets(
&mut type_converter,
&mut extra_apis,
)?,
TypedefKind::Use { .. } => Api::Typedef {
TypedefKind::Use(ref _itu, ref boxed_type) => Api::Typedef {
name,
item: item.clone(),
old_tyname,
analysis: TypedefAnalysis {
kind: item,
kind: item.clone(),
target: TypedefTargetType {
ty: boxed_type.as_ref().clone(),
is_reference: false,
},
deps: HashSet::new(),
},
},
Expand All @@ -96,10 +103,18 @@ fn get_replacement_typedef(
let mut converted_type = ity.clone();
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut converted_type.attrs);
metadata.check_for_fatal_attrs(&ity.ident)?;
let is_reference = metadata.has_attr("reference");
let type_conversion_context = if is_reference {
TypeConversionContext::OuterType {
pointer_treatment: PointerTreatment::Reference,
}
} else {
TypeConversionContext::WithinReference
};
let type_conversion_results = type_converter.convert_type(
(*ity.ty).clone(),
name.name.get_namespace(),
&TypeConversionContext::WithinReference,
&type_conversion_context,
);
match type_conversion_results {
Err(err) => Err(ConvertErrorWithContext(
Expand All @@ -120,9 +135,12 @@ fn get_replacement_typedef(
name,
item: TypedefKind::Type(ity.into()),
old_tyname,
is_reference,
analysis: TypedefAnalysis {
kind: TypedefKind::Type(converted_type.into()),
target: TypedefTargetType {
ty: final_type.ty.into(),
is_reference: final_type.kind.is_reference(),
},
deps: final_type.types_encountered,
},
})
Expand Down
68 changes: 52 additions & 16 deletions engine/src/conversion/analysis/type_converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use crate::{
conversion::{
api::{AnalysisPhase, Api, ApiName, NullPhase, TypedefKind, UnanalyzedApi},
api::{AnalysisPhase, Api, ApiName, NullPhase, UnanalyzedApi},
apivec::ApiVec,
codegen_cpp::type_to_cpp::CppNameMap,
ConvertErrorFromCpp,
Expand Down Expand Up @@ -40,6 +40,15 @@ pub(crate) enum TypeKind {
MutableReference,
}

impl TypeKind {
pub(crate) fn is_reference(&self) -> bool {
matches!(
self,
Self::Reference | Self::RValueReference | Self::MutableReference
)
}
}

/// Results of some type conversion, annotated with a list of every type encountered,
/// and optionally any extra APIs we need in order to use this type.
pub(crate) struct Annotated<T> {
Expand Down Expand Up @@ -125,7 +134,7 @@ impl TypeConversionContext {
/// inspecting the pre-existing list of APIs.
pub(crate) struct TypeConverter<'a> {
types_found: HashSet<QualifiedName>,
typedefs: HashMap<QualifiedName, Type>,
typedefs: HashMap<QualifiedName, TypedefTargetType>,
concrete_templates: HashMap<String, QualifiedName>,
forward_declarations: HashSet<QualifiedName>,
ignored_types: HashSet<QualifiedName>,
Expand Down Expand Up @@ -271,20 +280,33 @@ impl<'a> TypeConverter<'a> {
// First let's see if this is a typedef.
let (typ, tn) = match self.resolve_typedef(&original_tn)? {
None => (typ, original_tn),
Some(Type::Path(resolved_tp)) => {
Some(TypedefTargetType {
ty: crate::minisyn::Type(Type::Path(resolved_tp)),
..
}) => {
let resolved_tn = QualifiedName::from_type_path(resolved_tp);
deps.insert(resolved_tn.clone());
(resolved_tp.clone(), resolved_tn)
}
Some(Type::Ptr(resolved_tp)) => {
Some(TypedefTargetType {
ty: crate::minisyn::Type(Type::Ptr(resolved_tp)),
is_reference,
}) => {
return Ok(Annotated::new(
Type::Ptr(resolved_tp.clone()),
deps,
ApiVec::new(),
TypeKind::Pointer,
if *is_reference {
TypeKind::Reference
} else {
TypeKind::Pointer
},
))
}
Some(other) => {
Some(TypedefTargetType {
ty: crate::minisyn::Type(other),
..
}) => {
return Ok(Annotated::new(
other.clone(),
deps,
Expand Down Expand Up @@ -421,14 +443,17 @@ impl<'a> TypeConverter<'a> {
fn resolve_typedef<'b>(
&'b self,
tn: &QualifiedName,
) -> Result<Option<&'b Type>, ConvertErrorFromCpp> {
) -> Result<Option<&'b TypedefTargetType>, ConvertErrorFromCpp> {
let mut encountered = HashSet::new();
let mut tn = tn.clone();
let mut previous_typ = None;
loop {
let r = self.typedefs.get(&tn);
match r {
Some(Type::Path(typ)) => {
Some(TypedefTargetType {
ty: crate::minisyn::Type(Type::Path(typ)),
is_reference: false,
}) => {
previous_typ = r;
let new_tn = QualifiedName::from_type_path(typ);
if encountered.contains(&new_tn) {
Expand All @@ -445,6 +470,10 @@ impl<'a> TypeConverter<'a> {
encountered.insert(new_tn.clone());
tn = new_tn;
}
Some(TypedefTargetType {
ty: crate::minisyn::Type(Type::Path(_)),
is_reference: true,
}) => panic!("Only Type::Pointer should be a reference"),
None => return Ok(previous_typ),
_ => return Ok(r),
}
Expand Down Expand Up @@ -632,7 +661,9 @@ impl<'a> TypeConverter<'a> {
Ok(TypeKind::Regular)
}

fn find_typedefs<A: AnalysisPhase>(apis: &ApiVec<A>) -> HashMap<QualifiedName, Type>
fn find_typedefs<A: AnalysisPhase>(
apis: &ApiVec<A>,
) -> HashMap<QualifiedName, TypedefTargetType>
where
A::TypedefAnalysis: TypedefTarget,
{
Expand Down Expand Up @@ -705,22 +736,27 @@ pub(crate) fn add_analysis<A: AnalysisPhase>(api: UnanalyzedApi) -> Api<A> {
_ => panic!("Function analysis created an unexpected type of extra API"),
}
}

/// Target type of a typedef.
#[derive(Debug, Clone)]
pub(crate) struct TypedefTargetType {
pub(crate) ty: crate::minisyn::Type,
pub(crate) is_reference: bool,
}

pub(crate) trait TypedefTarget {
fn get_target(&self) -> Option<&Type>;
fn get_target(&self) -> Option<&TypedefTargetType>;
}

impl TypedefTarget for () {
fn get_target(&self) -> Option<&Type> {
fn get_target(&self) -> Option<&TypedefTargetType> {
None
}
}

impl TypedefTarget for TypedefAnalysis {
fn get_target(&self) -> Option<&Type> {
Some(match self.kind {
TypedefKind::Type(ref ty) => &ty.ty,
TypedefKind::Use(_, ref ty) => ty,
})
fn get_target(&self) -> Option<&TypedefTargetType> {
Some(&self.target)
}
}

Expand Down
3 changes: 0 additions & 3 deletions engine/src/conversion/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,6 @@ pub(crate) enum Api<T: AnalysisPhase> {
name: ApiName,
item: TypedefKind,
old_tyname: Option<QualifiedName>,
is_reference: bool,
analysis: T::TypedefAnalysis,
},
/// An enum encountered in the
Expand Down Expand Up @@ -667,7 +666,6 @@ impl<T: AnalysisPhase> Api<T> {
name: ApiName,
item: TypedefKind,
old_tyname: Option<QualifiedName>,
is_reference: bool,
analysis: T::TypedefAnalysis,
) -> Result<Box<dyn Iterator<Item = Api<T>>>, ConvertErrorWithContext>
where
Expand All @@ -677,7 +675,6 @@ impl<T: AnalysisPhase> Api<T> {
name,
item,
old_tyname,
is_reference,
analysis,
})))
}
Expand Down
4 changes: 1 addition & 3 deletions engine/src/conversion/error_reporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ pub(crate) fn convert_apis<FF, SF, EF, TF, A, B: 'static>(
ApiName,
TypedefKind,
Option<QualifiedName>,
bool,
A::TypedefAnalysis,
) -> Result<Box<dyn Iterator<Item = Api<B>>>, ConvertErrorWithContext>,
{
Expand Down Expand Up @@ -173,9 +172,8 @@ pub(crate) fn convert_apis<FF, SF, EF, TF, A, B: 'static>(
name,
item,
old_tyname,
is_reference,
analysis,
} => typedef_conversion(name, item, old_tyname, is_reference, analysis),
} => typedef_conversion(name, item, old_tyname, analysis),
Api::Function {
name,
fun,
Expand Down
2 changes: 1 addition & 1 deletion engine/src/conversion/parse/bindgen_semantic_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl BindgenSemanticAttributes {
}

/// Whether the given attribute is present.
pub(super) fn has_attr(&self, attr_name: &str) -> bool {
pub(crate) fn has_attr(&self, attr_name: &str) -> bool {
self.0.iter().any(|a| a.is_ident(attr_name))
}

Expand Down
3 changes: 0 additions & 3 deletions engine/src/conversion/parse/parse_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ impl<'a> ParseBindgen<'a> {
},
Box::new(Type::Path(old_path).into()),
),
is_reference: false,
old_tyname: Some(old_tyname),
analysis: (),
});
Expand Down Expand Up @@ -374,14 +373,12 @@ impl<'a> ParseBindgen<'a> {
}
Item::Type(ity) => {
let annotations = BindgenSemanticAttributes::new(&ity.attrs);
let is_reference = annotations.has_attr("reference");
// It's known that sometimes bindgen will give us duplicate typedefs with the
// same name - see test_issue_264.
self.apis.push(UnanalyzedApi::Typedef {
name: api_name(ns, ity.ident.clone(), &annotations),
item: TypedefKind::Type(ity.into()),
old_tyname: None,
is_reference,
analysis: (),
});
Ok(())
Expand Down

0 comments on commit 836b139

Please sign in to comment.