Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursively ignore items depending on ignored #288

Merged
merged 1 commit into from
Mar 20, 2021
Merged
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
1 change: 1 addition & 0 deletions engine/src/conversion/analysis/fun/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl<'a> FnAnalyzer<'a> {
analysis,
},
ApiDetail::OpaqueTypedef => ApiDetail::OpaqueTypedef,
ApiDetail::IgnoredItem => ApiDetail::IgnoredItem,
};
Ok(Some(Api {
ns: api.ns,
Expand Down
1 change: 1 addition & 0 deletions engine/src/conversion/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ pub(crate) mod ctypes;
pub(crate) mod fun;
pub(crate) mod gc;
pub(crate) mod pod; // hey, that rhymes
pub(crate) mod remove_ignored;
1 change: 1 addition & 0 deletions engine/src/conversion/analysis/pod/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ fn analyze_pod_api(
}
}
ApiDetail::OpaqueTypedef => ApiDetail::OpaqueTypedef,
ApiDetail::IgnoredItem => ApiDetail::IgnoredItem,
};
Ok(Api {
ns: api.ns,
Expand Down
55 changes: 55 additions & 0 deletions engine/src/conversion/analysis/remove_ignored.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashSet;

use super::fun::FnAnalysis;
use crate::conversion::api::{Api, ApiDetail};

/// Remove any APIs which depend on other items which have been ignored.
pub(crate) fn filter_apis_by_ignored_dependents(
mut apis: Vec<Api<FnAnalysis>>,
) -> Vec<Api<FnAnalysis>> {
let mut ignored_items: HashSet<_> = apis
.iter()
.filter_map(|api| {
if matches!(api.detail, ApiDetail::IgnoredItem) {
Some(api.typename())
} else {
None
}
})
.collect();
let mut iterate_again = true;
while iterate_again {
iterate_again = false;
apis = apis
.into_iter()
.filter(|api| {
if api.deps.iter().any(|dep| ignored_items.contains(dep)) {
iterate_again = true;
ignored_items.insert(api.typename());
eprintln!(
"Skipping item {} because it depends on another item we skipped.",
api.typename().to_string()
);
false
} else {
true
}
})
.collect();
}
apis
}
5 changes: 5 additions & 0 deletions engine/src/conversion/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ pub(crate) enum ApiDetail<T: ApiAnalysis> {
/// type, but instead to something which `bindgen` couldn't figure out
/// and has therefore itself made opaque and mysterious.
OpaqueTypedef,
/// Some item which couldn't be processed by autocxx for some reason.
/// We will have emitted a warning message about this, but we want
/// to mark that it's ignored so that we don't attempt to process
/// dependent items.
IgnoredItem,
}

/// Any API we encounter in the input bindgen rs which we might want to pass
Expand Down
10 changes: 10 additions & 0 deletions engine/src/conversion/codegen_rs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,16 @@ impl<'a> RsCodeGenerator<'a> {
})),
bindgen_mod_item: None,
},
ApiDetail::IgnoredItem => RsCodegenResult {
// In future it would be terrific to output something
// here which results in autocomplete in IDEs revealing
// the reason why this was ignored.
global_items: Vec::new(),
impl_entry: None,
bridge_items: Vec::new(),
extern_c_mod_item: None,
bindgen_mod_item: None,
},
}
}

Expand Down
10 changes: 9 additions & 1 deletion engine/src/conversion/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ use syn::{Item, ItemMod};
use crate::UnsafePolicy;

use self::{
analysis::{gc::filter_apis_by_following_edges_from_allowlist, pod::analyze_pod_apis},
analysis::{
gc::filter_apis_by_following_edges_from_allowlist, pod::analyze_pod_apis,
remove_ignored::filter_apis_by_ignored_dependents,
},
codegen_rs::RsCodeGenerator,
parse::ParseBindgen,
};
Expand Down Expand Up @@ -113,6 +116,11 @@ impl<'a> BridgeConverter<'a> {
&mut type_converter,
self.type_config,
)?;
// During parsing or subsequent processing we might have encountered
// items which we couldn't process due to as-yet-unsupported features.
// There might be other items depending on such things. Let's remove them
// too.
let analyzed_apis = filter_apis_by_ignored_dependents(analyzed_apis);
// We now garbage collect the ones we don't need...
let mut analyzed_apis =
filter_apis_by_following_edges_from_allowlist(analyzed_apis, &self.type_config);
Expand Down
50 changes: 39 additions & 11 deletions engine/src/conversion/parse/parse_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ pub(crate) struct ParseBindgen<'a> {
latest_virtual_this_type: Option<TypeName>,
}

struct ConvertErrorWithIdent(ConvertError, Option<Ident>);

impl std::fmt::Debug for ConvertErrorWithIdent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}

impl<'a> ParseBindgen<'a> {
pub(crate) fn new(type_config: &'a TypeConfig) -> Self {
ParseBindgen {
Expand Down Expand Up @@ -99,8 +107,18 @@ impl<'a> ParseBindgen<'a> {
for item in items {
let r = self.parse_item(item, &mut mod_converter, &ns);
match r {
Err(err) if err.is_ignorable() => {
eprintln!("Ignored item discovered whilst parsing: {}", err)
Err(err) if err.0.is_ignorable() => {
eprintln!("Ignored item discovered whilst parsing: {}", err.0);
// Mark that we ignored an item such that dependent things
// also can be ignored.
if let Some(id) = err.1 {
self.results.apis.push(UnanalyzedApi {
ns: ns.clone(),
id,
deps: HashSet::new(),
detail: ApiDetail::IgnoredItem,
})
}
}
Err(_) => r.unwrap(),
Ok(_) => {}
Expand All @@ -114,10 +132,13 @@ impl<'a> ParseBindgen<'a> {
item: Item,
mod_converter: &mut ParseForeignMod,
ns: &Namespace,
) -> Result<(), ConvertError> {
) -> Result<(), ConvertErrorWithIdent> {
match item {
Item::ForeignMod(fm) => mod_converter
.convert_foreign_mod_items(fm.items, self.latest_virtual_this_type.clone()),
Item::ForeignMod(fm) => {
mod_converter
.convert_foreign_mod_items(fm.items, self.latest_virtual_this_type.clone());
Ok(())
}
Item::Struct(s) => {
if s.ident.to_string().ends_with("__bindgen_vtable") {
return Ok(());
Expand Down Expand Up @@ -188,7 +209,10 @@ impl<'a> ParseBindgen<'a> {
};
let old_tyname = TypeName::from_type_path(&old_path);
if new_tyname == old_tyname {
return Err(ConvertError::InfinitelyRecursiveTypedef(new_tyname));
return Err(ConvertErrorWithIdent(
ConvertError::InfinitelyRecursiveTypedef(new_tyname),
Some(new_id.clone()),
));
}
self.results
.type_converter
Expand Down Expand Up @@ -233,13 +257,14 @@ impl<'a> ParseBindgen<'a> {
self.add_opaque_type(ity.ident, ns.clone());
Ok(())
}
Err(err) => Err(err),
Err(err) => Err(ConvertErrorWithIdent(err, Some(ity.ident))),
Ok(Annotated {
ty: syn::Type::Path(ref typ),
..
}) if TypeName::from_type_path(typ) == tyname => {
Err(ConvertError::InfinitelyRecursiveTypedef(tyname))
}
}) if TypeName::from_type_path(typ) == tyname => Err(ConvertErrorWithIdent(
ConvertError::InfinitelyRecursiveTypedef(tyname),
Some(ity.ident),
)),
Ok(mut final_type) => {
ity.ty = Box::new(final_type.ty.clone());
self.results
Expand All @@ -258,7 +283,10 @@ impl<'a> ParseBindgen<'a> {
}
}
}
_ => Err(ConvertError::UnexpectedItemInMod),
_ => Err(ConvertErrorWithIdent(
ConvertError::UnexpectedItemInMod,
None,
)),
}
}

Expand Down
3 changes: 1 addition & 2 deletions engine/src/conversion/parse/parse_foreign_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl ParseForeignMod {
&mut self,
foreign_mod_items: Vec<ForeignItem>,
virtual_this_type: Option<TypeName>,
) -> Result<(), ConvertError> {
) {
for i in foreign_mod_items {
let r = self.parse_foreign_item(i, &virtual_this_type);
match r {
Expand All @@ -64,7 +64,6 @@ impl ParseForeignMod {
Ok(_) => {}
}
}
Ok(())
}

fn parse_foreign_item(
Expand Down