Skip to content

Commit

Permalink
Refactor imports_granularity_one to avoid unreachable! arm
Browse files Browse the repository at this point in the history
  • Loading branch information
magurotuna committed Mar 20, 2021
1 parent 7e7ceb9 commit e2d9199
Showing 1 changed file with 79 additions and 67 deletions.
146 changes: 79 additions & 67 deletions src/formatting/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,29 @@ impl UseSegment {
}
}

// Check if self == other with their aliases removed.
fn equal_except_alias(&self, other: &Self) -> bool {
match (self, other) {
(UseSegment::Ident(ref s1, _), UseSegment::Ident(ref s2, _)) => s1 == s2,
(UseSegment::Slf(_), UseSegment::Slf(_))
| (UseSegment::Super(_), UseSegment::Super(_))
| (UseSegment::Crate(_), UseSegment::Crate(_))
| (UseSegment::Glob, UseSegment::Glob) => true,
(UseSegment::List(ref list1), UseSegment::List(ref list2)) => list1 == list2,
_ => false,
}
}

fn get_alias(&self) -> Option<&str> {
match self {
UseSegment::Ident(_, a)
| UseSegment::Slf(a)
| UseSegment::Super(a)
| UseSegment::Crate(a) => a.as_deref(),
_ => None,
}
}

fn from_path_segment(
context: &RewriteContext<'_>,
path_seg: &ast::PathSegment,
Expand All @@ -166,15 +189,6 @@ impl UseSegment {

pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>, merge_by: SharedPrefix) -> Vec<UseTree> {
let mut result = Vec::with_capacity(use_trees.len());

// If `merge_by` is `SharedPrefix::One`, we firstly compute the result as if it's
// `SharedPrefix::Crate`, and then merge the result one more time.
let temp_merge_by = if merge_by == SharedPrefix::One {
SharedPrefix::Crate
} else {
merge_by
};

for use_tree in use_trees {
if use_tree.has_comment() || use_tree.attrs.is_some() {
result.push(use_tree);
Expand All @@ -196,19 +210,14 @@ pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>, merge_by: SharedPrefix) -
}
if let Some(tree) = result
.iter_mut()
.find(|tree| tree.share_prefix(&flattened, temp_merge_by))
.find(|tree| tree.share_prefix(&flattened, merge_by))
{
tree.merge(&flattened, temp_merge_by);
tree.merge(&flattened, merge_by);
} else {
result.push(flattened);
}
}
}

if merge_by == SharedPrefix::One {
result = merge_use_trees_into_one(result);
}

result
}

Expand Down Expand Up @@ -593,7 +602,7 @@ impl UseTree {
SharedPrefix::Module => {
self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1]
}
SharedPrefix::One => unreachable!(),
SharedPrefix::One => true,
}
}
}
Expand Down Expand Up @@ -631,7 +640,7 @@ impl UseTree {
fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) {
let mut prefix = 0;
for (a, b) in self.path.iter().zip(other.path.iter()) {
if *a == *b {
if a.equal_except_alias(b) {
prefix += 1;
} else {
break;
Expand Down Expand Up @@ -666,14 +675,20 @@ fn merge_rest(
return Some(new_path);
}
} else if len == 1 {
let rest = if a.len() == len { &b[1..] } else { &a[1..] };
return Some(vec![
b[0].clone(),
UseSegment::List(vec![
UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
UseTree::from_path(rest.to_vec(), DUMMY_SP),
]),
]);
let (common, rest) = if a.len() == len {
(&a[0], &b[1..])
} else {
(&b[0], &a[1..])
};
let mut list = vec![UseTree::from_path(
vec![UseSegment::Slf(common.get_alias().map(ToString::to_string))],
DUMMY_SP,
)];
match rest {
[UseSegment::List(rest_list)] => list.extend(rest_list.clone()),
_ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
}
return Some(vec![b[0].clone(), UseSegment::List(list)]);
} else {
len -= 1;
}
Expand All @@ -688,58 +703,55 @@ fn merge_rest(
}

fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
let similar_trees = trees
.iter_mut()
.filter(|tree| tree.share_prefix(&use_tree, merge_by));
struct SimilarTree<'a> {
similarity: usize,
path_len: usize,
tree: &'a mut UseTree,
}

let similar_trees = trees.iter_mut().filter_map(|tree| {
if tree.share_prefix(&use_tree, merge_by) {
let similarity = tree
.path
.iter()
.zip(&use_tree.path)
.take_while(|(a, b)| a.equal_except_alias(b))
.count();
let path_len = tree.path.len();
Some(SimilarTree {
similarity,
tree,
path_len,
})
} else {
None
}
});

if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate {
if let Some(tree) = similar_trees.min_by_key(|tree| tree.path.len()) {
if tree.path.len() == 1 {
if let Some(tree) = similar_trees.min_by_key(|tree| tree.path_len) {
if tree.path_len == 1 {
return;
}
}
} else if merge_by == SharedPrefix::One {
if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.similarity) {
if sim_tree.similarity > 0 {
sim_tree.tree.merge(&use_tree, merge_by);
return;
}
}
} else if let Some(tree) = similar_trees.max_by_key(|tree| tree.path.len()) {
if tree.path.len() > 1 {
tree.merge(&use_tree, merge_by);
} else if let Some(sim_tree) = similar_trees.max_by_key(|tree| (tree.path_len, tree.similarity))
{
if sim_tree.path_len > 1 {
sim_tree.tree.merge(&use_tree, merge_by);
return;
}
}
trees.push(use_tree);
trees.sort();
}

fn merge_use_trees_into_one(trees: Vec<UseTree>) -> Vec<UseTree> {
let mut result = vec![];
for mut tree in trees {
if tree.attrs.is_some() {
result.push(tree);
} else if let Some(UseSegment::List(list)) = result.iter_mut().find_map(|r| {
if r.same_visibility(&tree) && r.attrs.is_none() {
r.path.get_mut(0)
} else {
None
}
}) {
list.push(tree);
} else {
tree.path = vec![UseSegment::List(vec![tree.clone()])];
result.push(tree);
}
}

// As a result of merging into one, if a `UseTree` has only one crate path just like
// `use {a::{b, c}}`, outmost curly braces can be removed.
for r in result.iter_mut() {
match r.path.get(0) {
Some(UseSegment::List(list)) if r.path.len() == 1 && list.len() == 1 => {
*r = list[0].clone();
}
_ => {}
}
}

result
}

impl Hash for UseTree {
fn hash<H: Hasher>(&self, state: &mut H) {
self.path.hash(state);
Expand Down

0 comments on commit e2d9199

Please sign in to comment.