Skip to content

Commit 8ebd201

Browse files
authored
Merge pull request #911 from google/never-panic-on-push-partial
Never panic on pushing API
2 parents 150274a + d7cd29f commit 8ebd201

File tree

15 files changed

+220
-188
lines changed

15 files changed

+220
-188
lines changed

engine/src/conversion/analysis/fun/mod.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ use crate::{
2424
UnsafetyNeeded, Virtualness,
2525
},
2626
apivec::ApiVec,
27-
convert_error::ConvertErrorWithContext,
2827
convert_error::ErrorContext,
28+
convert_error::{ConvertErrorWithContext, ErrorContextType},
2929
error_reporter::{convert_apis, report_any_error},
3030
},
3131
known_types::known_types,
@@ -963,7 +963,7 @@ impl<'a> FnAnalyzer<'a> {
963963
let rust_name = self.get_function_overload_name(ns, ideal_rust_name);
964964
(
965965
FnKind::Function,
966-
ErrorContext::Item(make_ident(&rust_name)),
966+
ErrorContext::new_for_item(make_ident(&rust_name)),
967967
rust_name,
968968
)
969969
};
@@ -1489,7 +1489,7 @@ impl<'a> FnAnalyzer<'a> {
14891489
trait_call_is_unsafe: false,
14901490
}),
14911491
},
1492-
ErrorContext::Item(make_ident(&rust_name)),
1492+
ErrorContext::new_for_item(make_ident(&rust_name)),
14931493
rust_name,
14941494
))
14951495
}
@@ -1534,7 +1534,7 @@ impl<'a> FnAnalyzer<'a> {
15341534
}),
15351535
kind,
15361536
},
1537-
ErrorContext::Item(make_ident(&rust_name)),
1537+
ErrorContext::new_for_item(make_ident(&rust_name)),
15381538
rust_name,
15391539
))
15401540
}
@@ -1956,14 +1956,11 @@ impl<'a> FnAnalyzer<'a> {
19561956
}
19571957

19581958
fn error_context_for_method(self_ty: &QualifiedName, rust_name: &str) -> ErrorContext {
1959-
ErrorContext::Method {
1960-
self_ty: self_ty.get_final_ident(),
1961-
method: make_ident(rust_name),
1962-
}
1959+
ErrorContext::new_for_method(self_ty.get_final_ident(), make_ident(rust_name))
19631960
}
19641961

19651962
impl Api<FnPhase> {
1966-
pub(crate) fn typename_for_allowlist(&self) -> QualifiedName {
1963+
pub(crate) fn name_for_allowlist(&self) -> QualifiedName {
19671964
match &self {
19681965
Api::Function { analysis, .. } => match analysis.kind {
19691966
FnKind::Method { ref impl_for, .. } => impl_for.clone(),
@@ -1973,6 +1970,19 @@ impl Api<FnPhase> {
19731970
}
19741971
},
19751972
Api::RustSubclassFn { subclass, .. } => subclass.0.name.clone(),
1973+
Api::IgnoredItem {
1974+
name,
1975+
ctx: Some(ctx),
1976+
..
1977+
} => match ctx.get_type() {
1978+
ErrorContextType::Method { self_ty, .. } => {
1979+
QualifiedName::new(name.name.get_namespace(), self_ty.clone())
1980+
}
1981+
ErrorContextType::Item(id) => {
1982+
QualifiedName::new(name.name.get_namespace(), id.clone())
1983+
}
1984+
_ => name.name.clone(),
1985+
},
19761986
_ => self.name().clone(),
19771987
}
19781988
}

engine/src/conversion/analysis/gc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub(crate) fn filter_apis_by_following_edges_from_allowlist(
4141
let mut todos: Vec<QualifiedName> = apis
4242
.iter()
4343
.filter(|api| {
44-
let tnforal = api.typename_for_allowlist();
44+
let tnforal = api.name_for_allowlist();
4545
config.is_on_allowlist(&tnforal.to_cpp_name())
4646
})
4747
.map(Api::name)

engine/src/conversion/analysis/pod/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ fn analyze_struct(
135135
if details.vis != CppVisibility::Public {
136136
return Err(ConvertErrorWithContext(
137137
ConvertError::NonPublicNestedType,
138-
Some(ErrorContext::Item(id)),
138+
Some(ErrorContext::new_for_item(id)),
139139
));
140140
}
141141
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut details.item.attrs);
@@ -157,11 +157,14 @@ fn analyze_struct(
157157
if details.has_rvalue_reference_fields {
158158
return Err(ConvertErrorWithContext(
159159
ConvertError::RValueReferenceField,
160-
Some(ErrorContext::Item(id)),
160+
Some(ErrorContext::new_for_item(id)),
161161
));
162162
}
163163
if let Some(err) = field_conversion_errors.into_iter().next() {
164-
return Err(ConvertErrorWithContext(err, Some(ErrorContext::Item(id))));
164+
return Err(ConvertErrorWithContext(
165+
err,
166+
Some(ErrorContext::new_for_item(id)),
167+
));
165168
}
166169
TypeKind::Pod
167170
} else {

engine/src/conversion/analysis/remove_ignored.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,9 @@ use crate::{conversion::api::Api, known_types};
1919
/// know about at all. In either case, we don't simply remove the type, but instead
2020
/// replace it with an error marker.
2121
pub(crate) fn filter_apis_by_ignored_dependents(mut apis: ApiVec<FnPhase>) -> ApiVec<FnPhase> {
22-
let (ignored_items, valid_items): (Vec<&Api<_>>, Vec<&Api<_>>) = apis.iter().partition(|api| {
23-
matches!(
24-
api,
25-
Api::IgnoredItem {
26-
ctx: ErrorContext::Item(..),
27-
..
28-
}
29-
)
30-
});
22+
let (ignored_items, valid_items): (Vec<&Api<_>>, Vec<&Api<_>>) = apis
23+
.iter()
24+
.partition(|api| matches!(api, Api::IgnoredItem { .. }));
3125
let mut ignored_items: HashSet<_> = ignored_items
3226
.into_iter()
3327
.map(|api| api.name().clone())
@@ -83,7 +77,7 @@ fn create_ignore_item(api: Api<FnPhase>, err: ConvertError) -> Api<FnPhase> {
8377
..
8478
},
8579
..
86-
} => ErrorContext::NoCode,
80+
} => None,
8781
Api::Function {
8882
analysis:
8983
FnAnalysis {
@@ -94,11 +88,8 @@ fn create_ignore_item(api: Api<FnPhase>, err: ConvertError) -> Api<FnPhase> {
9488
..
9589
},
9690
..
97-
} => ErrorContext::Method {
98-
self_ty: self_ty.get_final_ident(),
99-
method: id,
100-
},
101-
_ => ErrorContext::Item(id),
91+
} => Some(ErrorContext::new_for_method(self_ty.get_final_ident(), id)),
92+
_ => Some(ErrorContext::new_for_item(id)),
10293
},
10394
}
10495
}

engine/src/conversion/analysis/tdef.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,14 @@ fn get_replacement_typedef(
9696
match type_conversion_results {
9797
Err(err) => Err(ConvertErrorWithContext(
9898
err,
99-
Some(ErrorContext::Item(name.name.get_final_ident())),
99+
Some(ErrorContext::new_for_item(name.name.get_final_ident())),
100100
)),
101101
Ok(Annotated {
102102
ty: syn::Type::Path(ref typ),
103103
..
104104
}) if QualifiedName::from_type_path(typ) == name.name => Err(ConvertErrorWithContext(
105105
ConvertError::InfinitelyRecursiveTypedef(name.name.clone()),
106-
Some(ErrorContext::Item(name.name.get_final_ident())),
106+
Some(ErrorContext::new_for_item(name.name.get_final_ident())),
107107
)),
108108
Ok(mut final_type) => {
109109
converted_type.ty = Box::new(final_type.ty.clone());

engine/src/conversion/api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ pub(crate) enum Api<T: AnalysisPhase> {
467467
IgnoredItem {
468468
name: ApiName,
469469
err: ConvertError,
470-
ctx: ErrorContext,
470+
ctx: Option<ErrorContext>,
471471
},
472472
/// A Rust type which is not a C++ type.
473473
RustType { name: ApiName, path: RustPath },

engine/src/conversion/apivec.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -53,32 +53,21 @@ impl<P: AnalysisPhase> ApiVec<P> {
5353
let already_contains = self.already_contains(name);
5454
if already_contains {
5555
if api.discard_duplicates() {
56+
// This is already an IgnoredItem or something else where
57+
// we can silently drop it.
5658
log::info!("Discarding duplicate API for {}", name);
5759
} else {
58-
panic!(
59-
"Already have an API with that name: {}. API was {:?}",
60-
name, api
60+
log::info!(
61+
"Duplicate API for {} - removing all of them and replacing with an IgnoredItem.",
62+
name
6163
);
64+
self.retain(|api| api.name() != name);
65+
self.push(Api::IgnoredItem {
66+
name: ApiName::new_from_qualified_name(name.clone()),
67+
err: ConvertError::DuplicateItemsFoundInParsing,
68+
ctx: Some(ErrorContext::new_for_item(name.get_final_ident())),
69+
})
6270
}
63-
}
64-
self.names.insert(name.clone());
65-
self.apis.push(api)
66-
}
67-
68-
pub(crate) fn push_eliminating_duplicates(&mut self, api: Api<P>) {
69-
let name = api.name();
70-
let already_contains = self.already_contains(name);
71-
if already_contains {
72-
log::info!(
73-
"Duplicate API for {} - removing all of them and replacing with an IgnoredItem.",
74-
name
75-
);
76-
self.retain(|api| api.name() != name);
77-
self.push(Api::IgnoredItem {
78-
name: ApiName::new_from_qualified_name(name.clone()),
79-
err: ConvertError::DuplicateItemsFoundInParsing,
80-
ctx: ErrorContext::Item(name.get_final_ident()),
81-
})
8271
} else {
8372
self.names.insert(name.clone());
8473
self.apis.push(api)

engine/src/conversion/codegen_rs/mod.rs

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use crate::{
3333
},
3434
doc_attr::get_doc_attr,
3535
},
36-
known_types::known_types,
3736
types::{make_ident, Namespace, QualifiedName},
3837
};
3938
use impl_item_creator::create_impl_items;
@@ -46,6 +45,7 @@ use self::{
4645
use super::{
4746
analysis::fun::{FnPhase, ReceiverMutability},
4847
api::{AnalysisPhase, Api, SubclassName, TypeKind, TypedefKind},
48+
convert_error::ErrorContextType,
4949
};
5050
use super::{
5151
api::{Layout, Provenance, RustSubclassFnDetails, SuperclassMethod, TraitImplSignature},
@@ -564,8 +564,12 @@ impl<'a> RsCodeGenerator<'a> {
564564
subclasses_with_a_single_trivial_constructor.contains(&name.0.name);
565565
self.generate_subclass(name, &superclass, methods, generate_peer_constructor)
566566
}
567-
Api::IgnoredItem { err, ctx, .. } => Self::generate_error_entry(err, ctx),
568-
Api::SubclassTraitItem { .. } => RsCodegenResult::default(),
567+
Api::IgnoredItem {
568+
err,
569+
ctx: Some(ctx),
570+
..
571+
} => Self::generate_error_entry(err, ctx),
572+
Api::IgnoredItem { .. } | Api::SubclassTraitItem { .. } => RsCodegenResult::default(),
569573
}
570574
}
571575

@@ -930,67 +934,46 @@ impl<'a> RsCodeGenerator<'a> {
930934
/// generated.
931935
fn generate_error_entry(err: ConvertError, ctx: ErrorContext) -> RsCodegenResult {
932936
let err = format!("autocxx bindings couldn't be generated: {}", err);
933-
let (impl_entry, materialization) = match ctx {
934-
ErrorContext::Item(id) => {
935-
let id = Self::sanitize_error_ident(&id).unwrap_or(id);
936-
(
937-
None,
938-
Some(Use::Custom(Box::new(parse_quote! {
939-
#[doc = #err]
940-
pub struct #id;
941-
}))),
942-
)
943-
}
944-
ErrorContext::Method { self_ty, method }
945-
if Self::sanitize_error_ident(&self_ty).is_none() =>
946-
{
947-
// This could go wrong if a separate error has caused
948-
// us to drop an entire type as well as one of its individual items.
949-
// Then we'll be applying an impl to a thing which doesn't exist. TODO.
950-
let method = Self::sanitize_error_ident(&method).unwrap_or(method);
951-
(
952-
Some(Box::new(ImplBlockDetails {
953-
item: parse_quote! {
954-
#[doc = #err]
955-
fn #method(_uhoh: autocxx::BindingGenerationFailure) {
956-
}
957-
},
958-
ty: self_ty,
959-
})),
960-
None,
961-
)
962-
}
963-
ErrorContext::Method { self_ty, method } => {
964-
// If the type can't be represented (e.g. u8) this would get fiddly.
965-
let id = make_ident(format!("{}_method_{}", self_ty, method));
966-
(
967-
None,
968-
Some(Use::Custom(Box::new(parse_quote! {
937+
let (impl_entry, bindgen_mod_item, materialization) = match ctx.into_type() {
938+
ErrorContextType::Item(id) => (
939+
// Populate within bindgen mod because impl blocks may attach.
940+
None,
941+
Some(parse_quote! {
942+
#[doc = #err]
943+
pub struct #id;
944+
}),
945+
Some(Use::SpecificNameFromBindgen(id)),
946+
),
947+
ErrorContextType::SanitizedItem(id) => (
948+
// Guaranteed to be no impl blocks - populate directly in output mod.
949+
None,
950+
None,
951+
Some(Use::Custom(Box::new(parse_quote! {
952+
#[doc = #err]
953+
pub struct #id;
954+
}))),
955+
),
956+
ErrorContextType::Method { self_ty, method } => (
957+
Some(Box::new(ImplBlockDetails {
958+
item: parse_quote! {
969959
#[doc = #err]
970-
pub struct #id;
971-
}))),
972-
)
973-
}
974-
ErrorContext::NoCode => (None, None),
960+
fn #method(_uhoh: autocxx::BindingGenerationFailure) {
961+
}
962+
},
963+
ty: self_ty,
964+
})),
965+
None,
966+
None,
967+
),
975968
};
976969
RsCodegenResult {
977970
impl_entry,
971+
bindgen_mod_items: bindgen_mod_item.into_iter().collect(),
978972
materializations: materialization.into_iter().collect(),
979973
..Default::default()
980974
}
981975
}
982976

983-
/// Because errors may be generated for invalid types or identifiers,
984-
/// we may need to scrub the name
985-
fn sanitize_error_ident(id: &Ident) -> Option<Ident> {
986-
let qn = QualifiedName::new(&Namespace::new(), id.clone());
987-
if known_types().conflicts_with_built_in_type(&qn) {
988-
Some(make_ident(format!("{}_autocxx_error", qn.get_final_item())))
989-
} else {
990-
None
991-
}
992-
}
993-
994977
fn generate_cxx_use_stmt(name: &QualifiedName, alias: Option<&Ident>) -> Item {
995978
let segs = Self::find_output_mod_root(name.get_namespace())
996979
.chain(std::iter::once(make_ident("cxxbridge")))

0 commit comments

Comments
 (0)