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

Refactor Imports #826

Merged
merged 5 commits into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions src/analysis/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ impl Bounds {
for used in &self.used {
match used.bound_type {
NoWrapper => (),
IsA(_) => imports.add("glib::object::IsA", None),
AsRef(_) => imports.add_used_type(&used.type_str, None),
IsA(_) => imports.add("glib::object::IsA"),
AsRef(_) => imports.add_used_type(&used.type_str),
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/analysis/child_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ pub fn analyze(
}

if !properties.is_empty() {
imports.add("glib::object::IsA", None);
imports.add("glib::object::IsA");
if let Some(s) = child_type.and_then(|typ| used_rust_type(env, typ, true).ok()) {
imports.add_used_type(&s, None);
imports.add_used_type(&s);
}
}

Expand All @@ -81,10 +81,10 @@ fn analyze_property(
let prop_name = nameutil::signal_to_snake(&*prop.name);
let doc_hidden = prop.doc_hidden;

imports.add("glib::Value", None);
imports.add("glib::StaticType", None);
imports.add("glib::Value");
imports.add("glib::StaticType");
if let Ok(s) = used_rust_type(env, typ, false) {
imports.add_used_type(&s, None);
imports.add_used_type(&s);
}

let get_out_ref_mode = RefMode::of(env, typ, library::ParameterDirection::Return);
Expand Down
2 changes: 1 addition & 1 deletion src/analysis/class_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn analyze_property(
}
if let Ok(ref s) = used_rust_type(env, prop.typ, false) {
if !s.contains("GString") {
imports.add_used_type(s, prop.version);
imports.add_used_type_with_version(s, prop.version);
}
}

Expand Down
32 changes: 18 additions & 14 deletions src/analysis/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ fn fixup_special_functions(
&& parameters.c_parameters[0].c_type == "gconstpointer"
{
fixup_gpointer_parameter(env, type_tid, is_boxed, parameters, 0);
imports.add("glib_sys", None);
imports.add("glib_sys");
}

if (name == "compare" || name == "equal" || name == "is_equal")
Expand All @@ -218,7 +218,7 @@ fn fixup_special_functions(
{
fixup_gpointer_parameter(env, type_tid, is_boxed, parameters, 0);
fixup_gpointer_parameter(env, type_tid, is_boxed, parameters, 1);
imports.add("glib_sys", None);
imports.add("glib_sys");
}
}

Expand Down Expand Up @@ -495,6 +495,8 @@ fn analyze_function(
let doc_hidden = configured_functions.iter().any(|f| f.doc_hidden);
let disable_length_detect = configured_functions.iter().any(|f| f.disable_length_detect);

imports.set_defaults(&version, &cfg_condition);

let ret = return_value::analyze(
env,
func,
Expand Down Expand Up @@ -646,26 +648,26 @@ fn analyze_function(
commented = true;
} else if !commented {
if !outs.is_empty() {
out_parameters::analyze_imports(env, &func.parameters, func.version, imports);
out_parameters::analyze_imports(env, &func.parameters, imports);
}
if let Some(AsyncTrampoline {
ref output_params, ..
}) = trampoline
{
out_parameters::analyze_imports(env, output_params, func.version, imports);
out_parameters::analyze_imports(env, output_params, imports);
}
}

if r#async && !commented {
if env.config.library_name != "Gio" {
imports.add("gio_sys", version);
imports.add("gio_sys");
imports.add_with_constraint("gio", version, Some("futures"));
}
imports.add("glib_sys", version);
imports.add("gobject_sys", version);
imports.add("std::ptr", version);
imports.add("glib_sys");
imports.add("gobject_sys");
imports.add("std::ptr");
imports.add("std::boxed::Box as Box_");
imports.add_with_constraint("futures::future", version, Some("futures"));
imports.add_with_constraint("std::boxed::Box as Box_", version, Some("futures"));

if let Some(ref trampoline) = trampoline {
for par in &trampoline.output_params {
Expand All @@ -692,7 +694,7 @@ fn analyze_function(
commented = true;
}
if !commented && callbacks.iter().any(|c| !c.scope.is_call()) {
imports.add("std::boxed::Box as Box_", None);
imports.add("std::boxed::Box as Box_");
}
}
if !commented {
Expand All @@ -704,11 +706,11 @@ fn analyze_function(
}
}

imports.add_used_types(&used_types, version);
imports.add_used_types(&used_types);
if ret.base_tid.is_some() {
imports.add("glib::object::Cast", None);
imports.add("glib::object::Cast");
}
imports.add("glib::translate::*", version);
imports.add("glib::translate::*");
bounds.update_imports(imports);
}
}
Expand All @@ -721,6 +723,8 @@ fn analyze_function(
let is_method = func.kind == library::FunctionKind::Method;
let assertion = SafetyAssertionMode::of(env, is_method, &parameters);

imports.reset_defaults();

Info {
name,
glib_name: func.c_identifier.as_ref().unwrap().clone(),
Expand Down Expand Up @@ -976,7 +980,7 @@ fn analyze_callback(
} else {
if !*commented {
for import in imports_to_add {
imports.add_used_type(&import, None);
imports.add_used_type(&import);
}
}
Some((
Expand Down
162 changes: 129 additions & 33 deletions src/analysis/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ pub struct Imports {
///
/// NOTE: Currently we don't need to support more than one such name.
defined: Option<String>,
map: BTreeMap<String, (Option<Version>, Vec<String>)>,
defaults: ImportConditions,
map: BTreeMap<String, ImportConditions>,
}

impl Imports {
pub fn new(gir: &Library) -> Imports {
Imports {
crate_name: make_crate_name(gir),
defined: None,
defaults: ImportConditions::default(),
map: BTreeMap::new(),
}
}
Expand All @@ -32,32 +34,66 @@ impl Imports {
Imports {
crate_name: make_crate_name(gir),
defined: Some(name.to_owned()),
defaults: ImportConditions::default(),
map: BTreeMap::new(),
}
}

pub fn set_defaults(&mut self, version: &Option<Version>, constraint: &Option<String>) {
let constraints = if let Some(constraint) = constraint {
vec![constraint.clone()]
} else {
vec![]
};
self.defaults = ImportConditions {
version: version.clone(),
constraints,
};
}

pub fn reset_defaults(&mut self) {
self.defaults.clear();
}

/// Declares that name should be available through its last path component.
///
/// For example, if name is `X::Y::Z` then it will be available as `Z`.
pub fn add(&mut self, name: &str, version: Option<Version>) {
/// Uses defaults
pub fn add(&mut self, name: &str) {
if let Some(ref defined) = self.defined {
if name == defined {
return;
}
}
if let Some(name) = self.strip_crate_name(name) {
let defaults = &self.defaults;
let entry = self
.map
.entry(name.to_owned())
.or_insert((version, Vec::new()));
if version < entry.0 {
*entry = (version, Vec::new());
} else {
*entry = (entry.0, Vec::new());
.or_insert_with(|| defaults.clone());
entry.update_version(self.defaults.version);
entry.update_constraints(self.defaults.constraints.clone());
}
}

/// Declares that name should be available through its last path component.
///
/// For example, if name is `X::Y::Z` then it will be available as `Z`.
pub fn add_with_version(&mut self, name: &str, version: Option<Version>) {
if let Some(ref defined) = self.defined {
if name == defined {
return;
}
}
if let Some(name) = self.strip_crate_name(name) {
let entry = self.map.entry(name.to_owned()).or_insert(ImportConditions {
version,
constraints: Vec::new(),
});
entry.update_version(version);
// Since there is no constraint on this import, if any constraint
// is present, we can just remove it.
entry.1.clear();
entry.constraints.clear();
}
}

Expand All @@ -79,51 +115,59 @@ impl Imports {
if let Some(name) = self.strip_crate_name(name) {
let entry = if let Some(constraint) = constraint {
let constraint = String::from(constraint);
let entry = self
.map
.entry(name.to_owned())
.or_insert((version, vec![constraint.clone()]));
// If the import is already present but doesn't have any constraint,
// we don't want to add one. Otherwise, we just check if the constraint
// is already present or not before adding it.
if !entry.1.is_empty() && !entry.1.iter().any(|x| x == &constraint) {
entry.1.push(constraint);
}
let entry = self.map.entry(name.to_owned()).or_insert(ImportConditions {
version,
constraints: vec![constraint.clone()],
});
entry.add_constraint(constraint);
entry
} else {
let entry = self
.map
.entry(name.to_owned())
.or_insert((version, Vec::new()));
let entry = self.map.entry(name.to_owned()).or_insert(ImportConditions {
version,
constraints: Vec::new(),
});
// Since there is no constraint on this import, if any constraint
// is present, we can just remove it.
entry.1.clear();
entry.constraints.clear();
entry
};
if version < entry.0 {
entry.0 = version;
}
entry.update_version(version);
}
}

/// Declares that name should be available through its full path.
///
/// For example, if name is `X::Y` then it will be available as `X::Y`.
pub fn add_used_type(&mut self, used_type: &str, version: Option<Version>) {
pub fn add_used_type(&mut self, used_type: &str) {
if let Some(i) = used_type.find("::") {
if i == 0 {
self.add(&used_type[2..], version);
self.add(&used_type[2..]);
} else {
self.add(&used_type[..i], version);
self.add(&used_type[..i]);
}
} else {
self.add(used_type, version);
self.add(used_type);
}
}

pub fn add_used_types(&mut self, used_types: &[String], version: Option<Version>) {
pub fn add_used_types(&mut self, used_types: &[String]) {
for s in used_types {
self.add_used_type(s, version);
self.add_used_type(s);
}
}

/// Declares that name should be available through its full path.
///
/// For example, if name is `X::Y` then it will be available as `X::Y`.
pub fn add_used_type_with_version(&mut self, used_type: &str, version: Option<Version>) {
if let Some(i) = used_type.find("::") {
if i == 0 {
self.add_with_version(&used_type[2..], version);
} else {
self.add_with_version(&used_type[..i], version);
}
} else {
self.add_with_version(used_type, version);
}
}

Expand All @@ -147,11 +191,63 @@ impl Imports {
}
}

pub fn iter(&self) -> Iter<'_, String, (Option<Version>, Vec<String>)> {
pub fn iter(&self) -> Iter<'_, String, ImportConditions> {
self.map.iter()
}
}

#[derive(Clone, Debug, Default)]
pub struct ImportConditions {
pub version: Option<Version>,
pub constraints: Vec<String>,
}

impl ImportConditions {
fn clear(&mut self) {
*self = ImportConditions::default();
}

fn update_version(&mut self, version: Option<Version>) {
if version < self.version {
self.version = version;
}
}

fn add_constraint(&mut self, constraint: String) {
// If the import is already present but doesn't have any constraint,
// we don't want to add one.
if self.constraints.is_empty() {
return;
}
// Otherwise, we just check if the constraint
// is already present or not before adding it.
if !self.constraints.iter().any(|x| x == &constraint) {
self.constraints.push(constraint);
}
}

fn update_constraints(&mut self, constraints: Vec<String>) {
// If the import is already present but doesn't have any constraint,
// we don't want to add one.
if self.constraints.is_empty() {
return;
}
if constraints.is_empty() {
// Since there is no constraint on this import, if any constraint
// is present, we can just remove it.
self.constraints.clear();
} else {
// Otherwise, we just check if the constraint
// is already present or not before adding it.
for constraint in constraints {
if !self.constraints.iter().any(|x| x == &constraint) {
self.constraints.push(constraint.clone());
}
}
}
}
}

fn make_crate_name(gir: &Library) -> String {
let name = gir.namespace(namespaces::MAIN).name.as_str();
if name == "GObject" {
Expand Down
Loading