Skip to content

Commit 81ce961

Browse files
committed
Fix imports formatting broken after AST change for use_nested_groups
The new feature isn't supported yet (the code will likely panic or behave unexpectedly if nested groups are used), but now rustfmt compiles again, passing all tests.
1 parent b8106eb commit 81ce961

File tree

2 files changed

+135
-127
lines changed

2 files changed

+135
-127
lines changed

src/imports.rs

+134-126
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::cmp::Ordering;
1313
use syntax::ast;
1414
use syntax::codemap::{BytePos, Span};
1515

16+
1617
use spanned::Spanned;
1718
use codemap::SpanUtils;
1819
use comment::combine_strs_with_missing_comments;
@@ -25,14 +26,6 @@ use types::{rewrite_path, PathContext};
2526
use utils::{format_visibility, mk_sp};
2627
use visitor::{rewrite_extern_crate, FmtVisitor};
2728

28-
fn path_of(a: &ast::ViewPath_) -> &ast::Path {
29-
match *a {
30-
ast::ViewPath_::ViewPathSimple(_, ref p)
31-
| ast::ViewPath_::ViewPathGlob(ref p)
32-
| ast::ViewPath_::ViewPathList(ref p, _) => p,
33-
}
34-
}
35-
3629
fn compare_path_segments(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
3730
a.identifier.name.as_str().cmp(&b.identifier.name.as_str())
3831
}
@@ -47,75 +40,76 @@ fn compare_paths(a: &ast::Path, b: &ast::Path) -> Ordering {
4740
a.segments.len().cmp(&b.segments.len())
4841
}
4942

50-
fn compare_path_list_items(a: &ast::PathListItem, b: &ast::PathListItem) -> Ordering {
51-
let a_name_str = &*a.node.name.name.as_str();
52-
let b_name_str = &*b.node.name.name.as_str();
53-
let name_ordering = if a_name_str == "self" {
54-
if b_name_str == "self" {
55-
Ordering::Equal
56-
} else {
57-
Ordering::Less
58-
}
59-
} else if b_name_str == "self" {
60-
Ordering::Greater
61-
} else {
62-
a_name_str.cmp(b_name_str)
63-
};
64-
if name_ordering == Ordering::Equal {
65-
match a.node.rename {
66-
Some(a_rename) => match b.node.rename {
67-
Some(b_rename) => a_rename.name.as_str().cmp(&b_rename.name.as_str()),
68-
None => Ordering::Greater,
69-
},
70-
None => Ordering::Less,
71-
}
72-
} else {
73-
name_ordering
74-
}
75-
}
43+
fn compare_use_trees(a: &ast::UseTree, b: &ast::UseTree, nested: bool) -> Ordering {
44+
use ast::UseTreeKind::*;
7645

77-
fn compare_path_list_item_lists(
78-
a_items: &[ast::PathListItem],
79-
b_items: &[ast::PathListItem],
80-
) -> Ordering {
81-
let mut a = a_items.to_owned();
82-
let mut b = b_items.to_owned();
83-
a.sort_by(|a, b| compare_path_list_items(a, b));
84-
b.sort_by(|a, b| compare_path_list_items(a, b));
85-
for comparison_pair in a.iter().zip(b.iter()) {
86-
let ord = compare_path_list_items(comparison_pair.0, comparison_pair.1);
87-
if ord != Ordering::Equal {
88-
return ord;
46+
// `use_nested_groups` is not yet supported, remove the `if !nested` when support will be
47+
// fully added
48+
if !nested {
49+
let paths_cmp = compare_paths(&a.prefix, &b.prefix);
50+
if paths_cmp != Ordering::Equal {
51+
return paths_cmp;
8952
}
9053
}
91-
a.len().cmp(&b.len())
92-
}
9354

94-
fn compare_view_path_types(a: &ast::ViewPath_, b: &ast::ViewPath_) -> Ordering {
95-
use syntax::ast::ViewPath_::*;
96-
match (a, b) {
97-
(&ViewPathSimple(..), &ViewPathSimple(..)) | (&ViewPathGlob(_), &ViewPathGlob(_)) => {
98-
Ordering::Equal
55+
match (&a.kind, &b.kind) {
56+
(&Simple(ident_a), &Simple(ident_b)) => {
57+
let name_a = &*a.prefix.segments.last().unwrap().identifier.name.as_str();
58+
let name_b = &*b.prefix.segments.last().unwrap().identifier.name.as_str();
59+
let name_ordering = if name_a == "self" {
60+
if name_b == "self" {
61+
Ordering::Equal
62+
} else {
63+
Ordering::Less
64+
}
65+
} else if name_b == "self" {
66+
Ordering::Greater
67+
} else {
68+
name_a.cmp(name_b)
69+
};
70+
if name_ordering == Ordering::Equal {
71+
if ident_a.name.as_str() != name_a {
72+
if ident_b.name.as_str() != name_b {
73+
ident_a.name.as_str().cmp(&ident_b.name.as_str())
74+
} else {
75+
Ordering::Greater
76+
}
77+
} else {
78+
Ordering::Less
79+
}
80+
} else {
81+
name_ordering
82+
}
9983
}
100-
(&ViewPathSimple(..), _) | (&ViewPathGlob(_), &ViewPathList(..)) => Ordering::Less,
101-
(&ViewPathList(_, ref a_items), &ViewPathList(_, ref b_items)) => {
102-
compare_path_list_item_lists(a_items, b_items)
84+
(&Glob, &Glob) => Ordering::Equal,
85+
(&Simple(_), _) | (&Glob, &Nested(_)) => Ordering::Less,
86+
(&Nested(ref a_items), &Nested(ref b_items)) => {
87+
let mut a = a_items
88+
.iter()
89+
.map(|&(ref tree, _)| tree.clone())
90+
.collect::<Vec<_>>();
91+
let mut b = b_items
92+
.iter()
93+
.map(|&(ref tree, _)| tree.clone())
94+
.collect::<Vec<_>>();
95+
a.sort_by(|a, b| compare_use_trees(a, b, true));
96+
b.sort_by(|a, b| compare_use_trees(a, b, true));
97+
for comparison_pair in a.iter().zip(b.iter()) {
98+
let ord = compare_use_trees(comparison_pair.0, comparison_pair.1, true);
99+
if ord != Ordering::Equal {
100+
return ord;
101+
}
102+
}
103+
a.len().cmp(&b.len())
103104
}
104-
(&ViewPathGlob(_), &ViewPathSimple(..)) | (&ViewPathList(..), _) => Ordering::Greater,
105-
}
106-
}
107-
108-
fn compare_view_paths(a: &ast::ViewPath_, b: &ast::ViewPath_) -> Ordering {
109-
match compare_paths(path_of(a), path_of(b)) {
110-
Ordering::Equal => compare_view_path_types(a, b),
111-
cmp => cmp,
105+
(&Glob, &Simple(_)) | (&Nested(_), _) => Ordering::Greater,
112106
}
113107
}
114108

115109
fn compare_use_items(context: &RewriteContext, a: &ast::Item, b: &ast::Item) -> Option<Ordering> {
116110
match (&a.node, &b.node) {
117-
(&ast::ItemKind::Use(ref a_vp), &ast::ItemKind::Use(ref b_vp)) => {
118-
Some(compare_view_paths(&a_vp.node, &b_vp.node))
111+
(&ast::ItemKind::Use(ref a_tree), &ast::ItemKind::Use(ref b_tree)) => {
112+
Some(compare_use_trees(&a_tree, &b_tree, false))
119113
}
120114
(&ast::ItemKind::ExternCrate(..), &ast::ItemKind::ExternCrate(..)) => {
121115
Some(context.snippet(a.span).cmp(&context.snippet(b.span)))
@@ -127,11 +121,7 @@ fn compare_use_items(context: &RewriteContext, a: &ast::Item, b: &ast::Item) ->
127121
// TODO (some day) remove unused imports, expand globs, compress many single
128122
// imports into a list import.
129123

130-
fn rewrite_view_path_prefix(
131-
path: &ast::Path,
132-
context: &RewriteContext,
133-
shape: Shape,
134-
) -> Option<String> {
124+
fn rewrite_prefix(path: &ast::Path, context: &RewriteContext, shape: Shape) -> Option<String> {
135125
let path_str = if path.segments.last().unwrap().identifier.to_string() == "self"
136126
&& path.segments.len() > 1
137127
{
@@ -146,29 +136,34 @@ fn rewrite_view_path_prefix(
146136
Some(path_str)
147137
}
148138

149-
impl Rewrite for ast::ViewPath {
139+
impl Rewrite for ast::UseTree {
150140
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
151-
match self.node {
152-
ast::ViewPath_::ViewPathList(ref path, ref path_list) => {
153-
rewrite_use_list(shape, path, path_list, self.span, context)
141+
match self.kind {
142+
ast::UseTreeKind::Nested(ref items) => {
143+
rewrite_nested_use_tree(shape, &self.prefix, items, self.span, context)
154144
}
155-
ast::ViewPath_::ViewPathGlob(ref path) => {
156-
// 4 = "::*".len()
145+
ast::UseTreeKind::Glob => {
157146
let prefix_shape = shape.sub_width(3)?;
158-
let path_str = rewrite_view_path_prefix(path, context, prefix_shape)?;
159-
Some(format!("{}::*", path_str))
147+
148+
if self.prefix.segments.len() > 0 {
149+
let path_str = rewrite_prefix(&self.prefix, context, prefix_shape)?;
150+
Some(format!("{}::*", path_str))
151+
} else {
152+
Some("*".into())
153+
}
160154
}
161-
ast::ViewPath_::ViewPathSimple(ident, ref path) => {
155+
ast::UseTreeKind::Simple(ident) => {
162156
let ident_str = ident.to_string();
157+
163158
// 4 = " as ".len()
164159
let prefix_shape = shape.sub_width(ident_str.len() + 4)?;
165-
let path_str = rewrite_view_path_prefix(path, context, prefix_shape)?;
160+
let path_str = rewrite_prefix(&self.prefix, context, prefix_shape)?;
166161

167-
Some(if path.segments.last().unwrap().identifier == ident {
168-
path_str
162+
if self.prefix.segments.last().unwrap().identifier == ident {
163+
Some(path_str)
169164
} else {
170-
format!("{} as {}", path_str, ident_str)
171-
})
165+
Some(format!("{} as {}", path_str, ident_str))
166+
}
172167
}
173168
}
174169
}
@@ -178,7 +173,7 @@ impl Rewrite for ast::ViewPath {
178173
fn rewrite_import(
179174
context: &RewriteContext,
180175
vis: &ast::Visibility,
181-
vp: &ast::ViewPath,
176+
tree: &ast::UseTree,
182177
attrs: &[ast::Attribute],
183178
shape: Shape,
184179
) -> Option<String> {
@@ -187,14 +182,12 @@ fn rewrite_import(
187182
let rw = shape
188183
.offset_left(vis.len() + 4)
189184
.and_then(|shape| shape.sub_width(1))
190-
.and_then(|shape| match vp.node {
191-
// If we have an empty path list with no attributes, we erase it
192-
ast::ViewPath_::ViewPathList(_, ref path_list)
193-
if path_list.is_empty() && attrs.is_empty() =>
194-
{
185+
.and_then(|shape| match tree.kind {
186+
// If we have an empty nested group with no attributes, we erase it
187+
ast::UseTreeKind::Nested(ref items) if items.is_empty() && attrs.is_empty() => {
195188
Some("".into())
196189
}
197-
_ => vp.rewrite(context, shape),
190+
_ => tree.rewrite(context, shape),
198191
});
199192
match rw {
200193
Some(ref s) if !s.is_empty() => Some(format!("{}use {};", vis, s)),
@@ -225,8 +218,8 @@ fn rewrite_imports(
225218
};
226219

227220
let item_str = match item.node {
228-
ast::ItemKind::Use(ref vp) => {
229-
rewrite_import(context, &item.vis, vp, &item.attrs, shape)?
221+
ast::ItemKind::Use(ref tree) => {
222+
rewrite_import(context, &item.vis, tree, &item.attrs, shape)?
230223
}
231224
ast::ItemKind::ExternCrate(..) => rewrite_extern_crate(context, item)?,
232225
_ => return None,
@@ -276,10 +269,10 @@ impl<'a> FmtVisitor<'a> {
276269
self.push_rewrite(span, rw);
277270
}
278271

279-
pub fn format_import(&mut self, item: &ast::Item, vp: &ast::ViewPath) {
272+
pub fn format_import(&mut self, item: &ast::Item, tree: &ast::UseTree) {
280273
let span = item.span;
281274
let shape = self.shape();
282-
let rw = rewrite_import(&self.get_context(), &item.vis, vp, &item.attrs, shape);
275+
let rw = rewrite_import(&self.get_context(), &item.vis, tree, &item.attrs, shape);
283276
match rw {
284277
Some(ref s) if s.is_empty() => {
285278
// Format up to last newline
@@ -304,34 +297,48 @@ impl<'a> FmtVisitor<'a> {
304297
}
305298
}
306299

307-
fn rewrite_single_use_list(path_str: String, vpi: &ast::PathListItem) -> String {
308-
let mut item_str = vpi.node.name.to_string();
309-
if item_str == "self" {
310-
item_str = "".to_owned();
311-
}
312-
let path_item_str = if path_str.is_empty() {
313-
if item_str.is_empty() {
314-
"self".to_owned()
300+
fn rewrite_nested_use_tree_single(path_str: String, tree: &ast::UseTree) -> String {
301+
if let ast::UseTreeKind::Simple(rename) = tree.kind {
302+
let ident = tree.prefix.segments.last().unwrap().identifier;
303+
let mut item_str = ident.name.to_string();
304+
if item_str == "self" {
305+
item_str = "".to_owned();
306+
}
307+
308+
let path_item_str = if path_str.is_empty() {
309+
if item_str.is_empty() {
310+
"self".to_owned()
311+
} else {
312+
item_str
313+
}
314+
} else if item_str.is_empty() {
315+
path_str
315316
} else {
316-
item_str
317+
format!("{}::{}", path_str, item_str)
318+
};
319+
320+
if ident == rename {
321+
path_item_str
322+
} else {
323+
format!("{} as {}", path_item_str, rename)
317324
}
318-
} else if item_str.is_empty() {
319-
path_str
320325
} else {
321-
format!("{}::{}", path_str, item_str)
322-
};
323-
append_alias(path_item_str, vpi)
326+
unimplemented!("`use_nested_groups` is not yet fully supported");
327+
}
324328
}
325329

326-
fn rewrite_path_item(vpi: &&ast::PathListItem) -> Option<String> {
327-
Some(append_alias(vpi.node.name.to_string(), vpi))
328-
}
330+
fn rewrite_nested_use_tree_item(tree: &&ast::UseTree) -> Option<String> {
331+
Some(if let ast::UseTreeKind::Simple(rename) = tree.kind {
332+
let ident = tree.prefix.segments.last().unwrap().identifier;
329333

330-
fn append_alias(path_item_str: String, vpi: &ast::PathListItem) -> String {
331-
match vpi.node.rename {
332-
Some(rename) => format!("{} as {}", path_item_str, rename),
333-
None => path_item_str,
334-
}
334+
if ident == rename {
335+
ident.name.to_string()
336+
} else {
337+
format!("{} as {}", ident.name.to_string(), rename)
338+
}
339+
} else {
340+
unimplemented!("`use_nested_groups` is not yet fully supported");
341+
})
335342
}
336343

337344
#[derive(Eq, PartialEq)]
@@ -408,22 +415,23 @@ impl<'a> Ord for ImportItem<'a> {
408415

409416
// Pretty prints a multi-item import.
410417
// If the path list is empty, it leaves the braces empty.
411-
fn rewrite_use_list(
418+
fn rewrite_nested_use_tree(
412419
shape: Shape,
413420
path: &ast::Path,
414-
path_list: &[ast::PathListItem],
421+
trees: &[(ast::UseTree, ast::NodeId)],
415422
span: Span,
416423
context: &RewriteContext,
417424
) -> Option<String> {
418425
// Returns a different option to distinguish `::foo` and `foo`
419426
let path_str = rewrite_path(context, PathContext::Import, None, path, shape)?;
420427

421-
match path_list.len() {
428+
match trees.len() {
422429
0 => {
423430
return rewrite_path(context, PathContext::Import, None, path, shape)
424431
.map(|path_str| format!("{}::{{}}", path_str));
425432
}
426-
1 => return Some(rewrite_single_use_list(path_str, &path_list[0])),
433+
// TODO: fix this
434+
1 => return Some(rewrite_nested_use_tree_single(path_str, &trees[0].0)),
427435
_ => (),
428436
}
429437

@@ -441,12 +449,12 @@ fn rewrite_use_list(
441449
let mut items = vec![ListItem::from_str("")];
442450
let iter = itemize_list(
443451
context.codemap,
444-
path_list.iter(),
452+
trees.iter().map(|ref tree| &tree.0),
445453
"}",
446454
",",
447-
|vpi| vpi.span.lo(),
448-
|vpi| vpi.span.hi(),
449-
rewrite_path_item,
455+
|tree| tree.span.lo(),
456+
|tree| tree.span.hi(),
457+
rewrite_nested_use_tree_item,
450458
context.codemap.span_after(span, "{"),
451459
span.hi(),
452460
false,

src/visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ impl<'a> FmtVisitor<'a> {
328328
}
329329

330330
match item.node {
331-
ast::ItemKind::Use(ref vp) => self.format_import(item, vp),
331+
ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
332332
ast::ItemKind::Impl(..) => {
333333
let snippet = self.snippet(item.span);
334334
let where_span_end = snippet

0 commit comments

Comments
 (0)