]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use std::borrow::Cow; |
2 | use std::cmp::Ordering; | |
3 | use std::fmt; | |
4 | ||
923072b8 FG |
5 | use core::hash::{Hash, Hasher}; |
6 | ||
7 | use itertools::Itertools; | |
8 | ||
f20569fa XL |
9 | use rustc_ast::ast::{self, UseTreeKind}; |
10 | use rustc_span::{ | |
11 | symbol::{self, sym}, | |
12 | BytePos, Span, DUMMY_SP, | |
13 | }; | |
14 | ||
15 | use crate::comment::combine_strs_with_missing_comments; | |
16 | use crate::config::lists::*; | |
923072b8 FG |
17 | use crate::config::ImportGranularity; |
18 | use crate::config::{Edition, IndentStyle, Version}; | |
f20569fa XL |
19 | use crate::lists::{ |
20 | definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator, | |
21 | }; | |
22 | use crate::rewrite::{Rewrite, RewriteContext}; | |
23 | use crate::shape::Shape; | |
24 | use crate::source_map::SpanUtils; | |
25 | use crate::spanned::Spanned; | |
26 | use crate::utils::{is_same_visibility, mk_sp, rewrite_ident}; | |
27 | use crate::visitor::FmtVisitor; | |
28 | ||
29 | /// Returns a name imported by a `use` declaration. | |
30 | /// E.g., returns `Ordering` for `std::cmp::Ordering` and `self` for `std::cmp::self`. | |
31 | pub(crate) fn path_to_imported_ident(path: &ast::Path) -> symbol::Ident { | |
32 | path.segments.last().unwrap().ident | |
33 | } | |
34 | ||
35 | impl<'a> FmtVisitor<'a> { | |
36 | pub(crate) fn format_import(&mut self, item: &ast::Item, tree: &ast::UseTree) { | |
37 | let span = item.span(); | |
38 | let shape = self.shape(); | |
39 | let rw = UseTree::from_ast( | |
40 | &self.get_context(), | |
41 | tree, | |
42 | None, | |
43 | Some(item.vis.clone()), | |
44 | Some(item.span.lo()), | |
45 | Some(item.attrs.clone()), | |
46 | ) | |
47 | .rewrite_top_level(&self.get_context(), shape); | |
48 | match rw { | |
49 | Some(ref s) if s.is_empty() => { | |
50 | // Format up to last newline | |
51 | let prev_span = mk_sp(self.last_pos, source!(self, span).lo()); | |
52 | let trimmed_snippet = self.snippet(prev_span).trim_end(); | |
53 | let span_end = self.last_pos + BytePos(trimmed_snippet.len() as u32); | |
54 | self.format_missing(span_end); | |
55 | // We have an excessive newline from the removed import. | |
56 | if self.buffer.ends_with('\n') { | |
57 | self.buffer.pop(); | |
58 | self.line_number -= 1; | |
59 | } | |
60 | self.last_pos = source!(self, span).hi(); | |
61 | } | |
62 | Some(ref s) => { | |
63 | self.format_missing_with_indent(source!(self, span).lo()); | |
64 | self.push_str(s); | |
65 | self.last_pos = source!(self, span).hi(); | |
66 | } | |
67 | None => { | |
68 | self.format_missing_with_indent(source!(self, span).lo()); | |
69 | self.format_missing(source!(self, span).hi()); | |
70 | } | |
71 | } | |
72 | } | |
73 | } | |
74 | ||
75 | // Ordering of imports | |
76 | ||
77 | // We order imports by translating to our own representation and then sorting. | |
78 | // The Rust AST data structures are really bad for this. Rustfmt applies a bunch | |
79 | // of normalisations to imports and since we want to sort based on the result | |
80 | // of these (and to maintain idempotence) we must apply the same normalisations | |
81 | // to the data structures for sorting. | |
82 | // | |
83 | // We sort `self` and `super` before other imports, then identifier imports, | |
84 | // then glob imports, then lists of imports. We do not take aliases into account | |
85 | // when ordering unless the imports are identical except for the alias (rare in | |
86 | // practice). | |
87 | ||
88 | // FIXME(#2531): we should unify the comparison code here with the formatting | |
89 | // code elsewhere since we are essentially string-ifying twice. Furthermore, by | |
90 | // parsing to our own format on comparison, we repeat a lot of work when | |
91 | // sorting. | |
92 | ||
93 | // FIXME we do a lot of allocation to make our own representation. | |
923072b8 FG |
94 | #[derive(Clone, Eq, Hash, PartialEq)] |
95 | pub(crate) enum UseSegmentKind { | |
f20569fa XL |
96 | Ident(String, Option<String>), |
97 | Slf(Option<String>), | |
98 | Super(Option<String>), | |
99 | Crate(Option<String>), | |
100 | Glob, | |
101 | List(Vec<UseTree>), | |
102 | } | |
103 | ||
923072b8 FG |
104 | #[derive(Clone, Eq, PartialEq)] |
105 | pub(crate) struct UseSegment { | |
106 | pub(crate) kind: UseSegmentKind, | |
107 | pub(crate) version: Version, | |
108 | } | |
109 | ||
f20569fa XL |
110 | #[derive(Clone)] |
111 | pub(crate) struct UseTree { | |
112 | pub(crate) path: Vec<UseSegment>, | |
113 | pub(crate) span: Span, | |
114 | // Comment information within nested use tree. | |
115 | pub(crate) list_item: Option<ListItem>, | |
116 | // Additional fields for top level use items. | |
117 | // Should we have another struct for top-level use items rather than reusing this? | |
118 | visibility: Option<ast::Visibility>, | |
f2b60f7d | 119 | attrs: Option<ast::AttrVec>, |
f20569fa XL |
120 | } |
121 | ||
122 | impl PartialEq for UseTree { | |
123 | fn eq(&self, other: &UseTree) -> bool { | |
124 | self.path == other.path | |
125 | } | |
126 | } | |
127 | impl Eq for UseTree {} | |
128 | ||
129 | impl Spanned for UseTree { | |
130 | fn span(&self) -> Span { | |
131 | let lo = if let Some(ref attrs) = self.attrs { | |
132 | attrs.iter().next().map_or(self.span.lo(), |a| a.span.lo()) | |
133 | } else { | |
134 | self.span.lo() | |
135 | }; | |
136 | mk_sp(lo, self.span.hi()) | |
137 | } | |
138 | } | |
139 | ||
140 | impl UseSegment { | |
141 | // Clone a version of self with any top-level alias removed. | |
142 | fn remove_alias(&self) -> UseSegment { | |
923072b8 FG |
143 | let kind = match self.kind { |
144 | UseSegmentKind::Ident(ref s, _) => UseSegmentKind::Ident(s.clone(), None), | |
145 | UseSegmentKind::Slf(_) => UseSegmentKind::Slf(None), | |
146 | UseSegmentKind::Super(_) => UseSegmentKind::Super(None), | |
147 | UseSegmentKind::Crate(_) => UseSegmentKind::Crate(None), | |
148 | _ => return self.clone(), | |
149 | }; | |
150 | UseSegment { | |
151 | kind, | |
152 | version: self.version, | |
f20569fa XL |
153 | } |
154 | } | |
155 | ||
3c0e092e XL |
156 | // Check if self == other with their aliases removed. |
157 | fn equal_except_alias(&self, other: &Self) -> bool { | |
923072b8 FG |
158 | match (&self.kind, &other.kind) { |
159 | (UseSegmentKind::Ident(ref s1, _), UseSegmentKind::Ident(ref s2, _)) => s1 == s2, | |
160 | (UseSegmentKind::Slf(_), UseSegmentKind::Slf(_)) | |
161 | | (UseSegmentKind::Super(_), UseSegmentKind::Super(_)) | |
162 | | (UseSegmentKind::Crate(_), UseSegmentKind::Crate(_)) | |
163 | | (UseSegmentKind::Glob, UseSegmentKind::Glob) => true, | |
164 | (UseSegmentKind::List(ref list1), UseSegmentKind::List(ref list2)) => list1 == list2, | |
3c0e092e XL |
165 | _ => false, |
166 | } | |
167 | } | |
168 | ||
169 | fn get_alias(&self) -> Option<&str> { | |
923072b8 FG |
170 | match &self.kind { |
171 | UseSegmentKind::Ident(_, a) | |
172 | | UseSegmentKind::Slf(a) | |
173 | | UseSegmentKind::Super(a) | |
174 | | UseSegmentKind::Crate(a) => a.as_deref(), | |
3c0e092e XL |
175 | _ => None, |
176 | } | |
177 | } | |
178 | ||
f20569fa XL |
179 | fn from_path_segment( |
180 | context: &RewriteContext<'_>, | |
181 | path_seg: &ast::PathSegment, | |
182 | modsep: bool, | |
183 | ) -> Option<UseSegment> { | |
184 | let name = rewrite_ident(context, path_seg.ident); | |
185 | if name.is_empty() || name == "{{root}}" { | |
186 | return None; | |
187 | } | |
923072b8 FG |
188 | let kind = match name { |
189 | "self" => UseSegmentKind::Slf(None), | |
190 | "super" => UseSegmentKind::Super(None), | |
191 | "crate" => UseSegmentKind::Crate(None), | |
f20569fa XL |
192 | _ => { |
193 | let mod_sep = if modsep { "::" } else { "" }; | |
923072b8 | 194 | UseSegmentKind::Ident(format!("{}{}", mod_sep, name), None) |
f20569fa | 195 | } |
923072b8 FG |
196 | }; |
197 | ||
198 | Some(UseSegment { | |
199 | kind, | |
200 | version: context.config.version(), | |
f20569fa XL |
201 | }) |
202 | } | |
923072b8 FG |
203 | |
204 | fn contains_comment(&self) -> bool { | |
205 | if let UseSegmentKind::List(list) = &self.kind { | |
206 | list.iter().any(|subtree| subtree.contains_comment()) | |
207 | } else { | |
208 | false | |
209 | } | |
210 | } | |
f20569fa XL |
211 | } |
212 | ||
923072b8 FG |
213 | pub(crate) fn normalize_use_trees_with_granularity( |
214 | use_trees: Vec<UseTree>, | |
215 | import_granularity: ImportGranularity, | |
216 | ) -> Vec<UseTree> { | |
217 | let merge_by = match import_granularity { | |
218 | ImportGranularity::Item => return flatten_use_trees(use_trees, ImportGranularity::Item), | |
219 | ImportGranularity::Preserve => return use_trees, | |
220 | ImportGranularity::Crate => SharedPrefix::Crate, | |
221 | ImportGranularity::Module => SharedPrefix::Module, | |
222 | ImportGranularity::One => SharedPrefix::One, | |
223 | }; | |
224 | ||
f20569fa XL |
225 | let mut result = Vec::with_capacity(use_trees.len()); |
226 | for use_tree in use_trees { | |
923072b8 | 227 | if use_tree.contains_comment() || use_tree.attrs.is_some() { |
f20569fa XL |
228 | result.push(use_tree); |
229 | continue; | |
230 | } | |
231 | ||
923072b8 | 232 | for mut flattened in use_tree.flatten(import_granularity) { |
f20569fa XL |
233 | if let Some(tree) = result |
234 | .iter_mut() | |
235 | .find(|tree| tree.share_prefix(&flattened, merge_by)) | |
236 | { | |
237 | tree.merge(&flattened, merge_by); | |
238 | } else { | |
5e7ed085 FG |
239 | // If this is the first tree with this prefix, handle potential trailing ::self |
240 | if merge_by == SharedPrefix::Module { | |
241 | flattened = flattened.nest_trailing_self(); | |
242 | } | |
f20569fa XL |
243 | result.push(flattened); |
244 | } | |
245 | } | |
246 | } | |
247 | result | |
248 | } | |
249 | ||
923072b8 FG |
250 | fn flatten_use_trees( |
251 | use_trees: Vec<UseTree>, | |
252 | import_granularity: ImportGranularity, | |
253 | ) -> Vec<UseTree> { | |
254 | // Return non-sorted single occurance of the use-trees text string; | |
255 | // order is by first occurance of the use-tree. | |
f20569fa XL |
256 | use_trees |
257 | .into_iter() | |
923072b8 | 258 | .flat_map(|tree| tree.flatten(import_granularity)) |
5e7ed085 | 259 | .map(UseTree::nest_trailing_self) |
923072b8 | 260 | .unique() |
f20569fa XL |
261 | .collect() |
262 | } | |
263 | ||
264 | impl fmt::Debug for UseTree { | |
265 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
266 | fmt::Display::fmt(self, f) | |
267 | } | |
268 | } | |
269 | ||
270 | impl fmt::Debug for UseSegment { | |
271 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
923072b8 | 272 | fmt::Display::fmt(&self.kind, f) |
f20569fa XL |
273 | } |
274 | } | |
275 | ||
276 | impl fmt::Display for UseSegment { | |
923072b8 FG |
277 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
278 | fmt::Display::fmt(&self.kind, f) | |
279 | } | |
280 | } | |
281 | ||
282 | impl Hash for UseSegment { | |
283 | fn hash<H: Hasher>(&self, state: &mut H) { | |
284 | self.kind.hash(state); | |
285 | } | |
286 | } | |
287 | ||
288 | impl fmt::Debug for UseSegmentKind { | |
289 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
290 | fmt::Display::fmt(self, f) | |
291 | } | |
292 | } | |
293 | ||
294 | impl fmt::Display for UseSegmentKind { | |
f20569fa XL |
295 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
296 | match *self { | |
923072b8 FG |
297 | UseSegmentKind::Glob => write!(f, "*"), |
298 | UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias), | |
299 | UseSegmentKind::Ident(ref s, None) => write!(f, "{}", s), | |
300 | UseSegmentKind::Slf(..) => write!(f, "self"), | |
301 | UseSegmentKind::Super(..) => write!(f, "super"), | |
302 | UseSegmentKind::Crate(..) => write!(f, "crate"), | |
303 | UseSegmentKind::List(ref list) => { | |
f20569fa XL |
304 | write!(f, "{{")?; |
305 | for (i, item) in list.iter().enumerate() { | |
306 | if i != 0 { | |
307 | write!(f, ", ")?; | |
308 | } | |
309 | write!(f, "{}", item)?; | |
310 | } | |
311 | write!(f, "}}") | |
312 | } | |
313 | } | |
314 | } | |
315 | } | |
316 | impl fmt::Display for UseTree { | |
317 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
318 | for (i, segment) in self.path.iter().enumerate() { | |
319 | if i != 0 { | |
320 | write!(f, "::")?; | |
321 | } | |
322 | write!(f, "{}", segment)?; | |
323 | } | |
324 | Ok(()) | |
325 | } | |
326 | } | |
327 | ||
328 | impl UseTree { | |
329 | // Rewrite use tree with `use ` and a trailing `;`. | |
330 | pub(crate) fn rewrite_top_level( | |
331 | &self, | |
332 | context: &RewriteContext<'_>, | |
333 | shape: Shape, | |
334 | ) -> Option<String> { | |
335 | let vis = self.visibility.as_ref().map_or(Cow::from(""), |vis| { | |
3c0e092e | 336 | crate::utils::format_visibility(context, vis) |
f20569fa XL |
337 | }); |
338 | let use_str = self | |
339 | .rewrite(context, shape.offset_left(vis.len())?) | |
340 | .map(|s| { | |
341 | if s.is_empty() { | |
342 | s | |
343 | } else { | |
344 | format!("{}use {};", vis, s) | |
345 | } | |
346 | })?; | |
347 | match self.attrs { | |
348 | Some(ref attrs) if !attrs.is_empty() => { | |
349 | let attr_str = attrs.rewrite(context, shape)?; | |
350 | let lo = attrs.last().as_ref()?.span.hi(); | |
351 | let hi = self.span.lo(); | |
352 | let span = mk_sp(lo, hi); | |
353 | ||
354 | let allow_extend = if attrs.len() == 1 { | |
355 | let line_len = attr_str.len() + 1 + use_str.len(); | |
356 | !attrs.first().unwrap().is_doc_comment() | |
357 | && context.config.inline_attribute_width() >= line_len | |
358 | } else { | |
359 | false | |
360 | }; | |
361 | ||
362 | combine_strs_with_missing_comments( | |
363 | context, | |
364 | &attr_str, | |
365 | &use_str, | |
366 | span, | |
367 | shape, | |
368 | allow_extend, | |
369 | ) | |
370 | } | |
371 | _ => Some(use_str), | |
372 | } | |
373 | } | |
374 | ||
375 | // FIXME: Use correct span? | |
376 | // The given span is essentially incorrect, since we are reconstructing | |
377 | // use-statements. This should not be a problem, though, since we have | |
378 | // already tried to extract comment and observed that there are no comment | |
379 | // around the given use item, and the span will not be used afterward. | |
380 | fn from_path(path: Vec<UseSegment>, span: Span) -> UseTree { | |
381 | UseTree { | |
382 | path, | |
383 | span, | |
384 | list_item: None, | |
385 | visibility: None, | |
386 | attrs: None, | |
387 | } | |
388 | } | |
389 | ||
390 | pub(crate) fn from_ast_with_normalization( | |
391 | context: &RewriteContext<'_>, | |
392 | item: &ast::Item, | |
393 | ) -> Option<UseTree> { | |
394 | match item.kind { | |
395 | ast::ItemKind::Use(ref use_tree) => Some( | |
396 | UseTree::from_ast( | |
397 | context, | |
398 | use_tree, | |
399 | None, | |
400 | Some(item.vis.clone()), | |
401 | Some(item.span.lo()), | |
402 | if item.attrs.is_empty() { | |
403 | None | |
404 | } else { | |
405 | Some(item.attrs.clone()) | |
406 | }, | |
407 | ) | |
408 | .normalize(), | |
409 | ), | |
410 | _ => None, | |
411 | } | |
412 | } | |
413 | ||
414 | fn from_ast( | |
415 | context: &RewriteContext<'_>, | |
416 | a: &ast::UseTree, | |
417 | list_item: Option<ListItem>, | |
418 | visibility: Option<ast::Visibility>, | |
419 | opt_lo: Option<BytePos>, | |
f2b60f7d | 420 | attrs: Option<ast::AttrVec>, |
f20569fa XL |
421 | ) -> UseTree { |
422 | let span = if let Some(lo) = opt_lo { | |
423 | mk_sp(lo, a.span.hi()) | |
424 | } else { | |
425 | a.span | |
426 | }; | |
427 | let mut result = UseTree { | |
428 | path: vec![], | |
429 | span, | |
430 | list_item, | |
431 | visibility, | |
432 | attrs, | |
433 | }; | |
434 | ||
435 | let leading_modsep = | |
436 | context.config.edition() >= Edition::Edition2018 && a.prefix.is_global(); | |
437 | ||
438 | let mut modsep = leading_modsep; | |
439 | ||
440 | for p in &a.prefix.segments { | |
441 | if let Some(use_segment) = UseSegment::from_path_segment(context, p, modsep) { | |
442 | result.path.push(use_segment); | |
443 | modsep = false; | |
444 | } | |
445 | } | |
446 | ||
923072b8 FG |
447 | let version = context.config.version(); |
448 | ||
f20569fa XL |
449 | match a.kind { |
450 | UseTreeKind::Glob => { | |
451 | // in case of a global path and the glob starts at the root, e.g., "::*" | |
452 | if a.prefix.segments.len() == 1 && leading_modsep { | |
923072b8 FG |
453 | let kind = UseSegmentKind::Ident("".to_owned(), None); |
454 | result.path.push(UseSegment { kind, version }); | |
f20569fa | 455 | } |
923072b8 FG |
456 | result.path.push(UseSegment { |
457 | kind: UseSegmentKind::Glob, | |
458 | version, | |
459 | }); | |
f20569fa XL |
460 | } |
461 | UseTreeKind::Nested(ref list) => { | |
462 | // Extract comments between nested use items. | |
463 | // This needs to be done before sorting use items. | |
94222f64 | 464 | let items = itemize_list( |
f20569fa XL |
465 | context.snippet_provider, |
466 | list.iter().map(|(tree, _)| tree), | |
467 | "}", | |
468 | ",", | |
469 | |tree| tree.span.lo(), | |
470 | |tree| tree.span.hi(), | |
471 | |_| Some("".to_owned()), // We only need comments for now. | |
472 | context.snippet_provider.span_after(a.span, "{"), | |
473 | a.span.hi(), | |
474 | false, | |
94222f64 XL |
475 | ); |
476 | ||
f20569fa XL |
477 | // in case of a global path and the nested list starts at the root, |
478 | // e.g., "::{foo, bar}" | |
479 | if a.prefix.segments.len() == 1 && leading_modsep { | |
923072b8 FG |
480 | let kind = UseSegmentKind::Ident("".to_owned(), None); |
481 | result.path.push(UseSegment { kind, version }); | |
f20569fa | 482 | } |
923072b8 | 483 | let kind = UseSegmentKind::List( |
f20569fa | 484 | list.iter() |
94222f64 | 485 | .zip(items) |
f20569fa XL |
486 | .map(|(t, list_item)| { |
487 | Self::from_ast(context, &t.0, Some(list_item), None, None, None) | |
488 | }) | |
489 | .collect(), | |
923072b8 FG |
490 | ); |
491 | result.path.push(UseSegment { kind, version }); | |
f20569fa | 492 | } |
487cf647 | 493 | UseTreeKind::Simple(ref rename) => { |
f20569fa XL |
494 | // If the path has leading double colons and is composed of only 2 segments, then we |
495 | // bypass the call to path_to_imported_ident which would get only the ident and | |
496 | // lose the path root, e.g., `that` in `::that`. | |
497 | // The span of `a.prefix` contains the leading colons. | |
498 | let name = if a.prefix.segments.len() == 2 && leading_modsep { | |
499 | context.snippet(a.prefix.span).to_owned() | |
500 | } else { | |
501 | rewrite_ident(context, path_to_imported_ident(&a.prefix)).to_owned() | |
502 | }; | |
503 | let alias = rename.and_then(|ident| { | |
504 | if ident.name == sym::underscore_imports { | |
505 | // for impl-only-use | |
506 | Some("_".to_owned()) | |
507 | } else if ident == path_to_imported_ident(&a.prefix) { | |
508 | None | |
509 | } else { | |
510 | Some(rewrite_ident(context, ident).to_owned()) | |
511 | } | |
512 | }); | |
923072b8 FG |
513 | let kind = match name.as_ref() { |
514 | "self" => UseSegmentKind::Slf(alias), | |
515 | "super" => UseSegmentKind::Super(alias), | |
516 | "crate" => UseSegmentKind::Crate(alias), | |
517 | _ => UseSegmentKind::Ident(name, alias), | |
f20569fa XL |
518 | }; |
519 | ||
923072b8 FG |
520 | let segment = UseSegment { kind, version }; |
521 | ||
f20569fa XL |
522 | // `name` is already in result. |
523 | result.path.pop(); | |
524 | result.path.push(segment); | |
525 | } | |
526 | } | |
527 | result | |
528 | } | |
529 | ||
530 | // Do the adjustments that rustfmt does elsewhere to use paths. | |
531 | pub(crate) fn normalize(mut self) -> UseTree { | |
532 | let mut last = self.path.pop().expect("Empty use tree?"); | |
533 | // Hack around borrow checker. | |
534 | let mut normalize_sole_list = false; | |
535 | let mut aliased_self = false; | |
536 | ||
537 | // Remove foo::{} or self without attributes. | |
923072b8 | 538 | match last.kind { |
f20569fa | 539 | _ if self.attrs.is_some() => (), |
923072b8 | 540 | UseSegmentKind::List(ref list) if list.is_empty() => { |
f20569fa XL |
541 | self.path = vec![]; |
542 | return self; | |
543 | } | |
923072b8 | 544 | UseSegmentKind::Slf(None) if self.path.is_empty() && self.visibility.is_some() => { |
f20569fa XL |
545 | self.path = vec![]; |
546 | return self; | |
547 | } | |
548 | _ => (), | |
549 | } | |
550 | ||
551 | // Normalise foo::self -> foo. | |
923072b8 | 552 | if let UseSegmentKind::Slf(None) = last.kind { |
f20569fa XL |
553 | if !self.path.is_empty() { |
554 | return self; | |
555 | } | |
556 | } | |
557 | ||
558 | // Normalise foo::self as bar -> foo as bar. | |
923072b8 FG |
559 | if let UseSegmentKind::Slf(_) = last.kind { |
560 | if let Some(UseSegment { | |
561 | kind: UseSegmentKind::Ident(_, None), | |
562 | .. | |
563 | }) = self.path.last() | |
564 | { | |
94222f64 | 565 | aliased_self = true; |
f20569fa XL |
566 | } |
567 | } | |
568 | ||
569 | let mut done = false; | |
570 | if aliased_self { | |
571 | match self.path.last_mut() { | |
923072b8 FG |
572 | Some(UseSegment { |
573 | kind: UseSegmentKind::Ident(_, ref mut old_rename), | |
574 | .. | |
575 | }) => { | |
f20569fa | 576 | assert!(old_rename.is_none()); |
923072b8 | 577 | if let UseSegmentKind::Slf(Some(rename)) = last.clone().kind { |
f20569fa XL |
578 | *old_rename = Some(rename); |
579 | done = true; | |
580 | } | |
581 | } | |
582 | _ => unreachable!(), | |
583 | } | |
584 | } | |
585 | ||
586 | if done { | |
587 | return self; | |
588 | } | |
589 | ||
590 | // Normalise foo::{bar} -> foo::bar | |
923072b8 | 591 | if let UseSegmentKind::List(ref list) = last.kind { |
f20569fa XL |
592 | if list.len() == 1 && list[0].to_string() != "self" { |
593 | normalize_sole_list = true; | |
594 | } | |
595 | } | |
596 | ||
597 | if normalize_sole_list { | |
923072b8 FG |
598 | match last.kind { |
599 | UseSegmentKind::List(list) => { | |
f20569fa XL |
600 | for seg in &list[0].path { |
601 | self.path.push(seg.clone()); | |
602 | } | |
603 | return self.normalize(); | |
604 | } | |
605 | _ => unreachable!(), | |
606 | } | |
607 | } | |
608 | ||
609 | // Recursively normalize elements of a list use (including sorting the list). | |
923072b8 | 610 | if let UseSegmentKind::List(list) = last.kind { |
f20569fa XL |
611 | let mut list = list.into_iter().map(UseTree::normalize).collect::<Vec<_>>(); |
612 | list.sort(); | |
923072b8 FG |
613 | last = UseSegment { |
614 | kind: UseSegmentKind::List(list), | |
615 | version: last.version, | |
616 | }; | |
f20569fa XL |
617 | } |
618 | ||
619 | self.path.push(last); | |
620 | self | |
621 | } | |
622 | ||
623 | fn has_comment(&self) -> bool { | |
624 | self.list_item.as_ref().map_or(false, ListItem::has_comment) | |
625 | } | |
626 | ||
923072b8 FG |
627 | fn contains_comment(&self) -> bool { |
628 | self.has_comment() || self.path.iter().any(|path| path.contains_comment()) | |
629 | } | |
630 | ||
f20569fa XL |
631 | fn same_visibility(&self, other: &UseTree) -> bool { |
632 | match (&self.visibility, &other.visibility) { | |
633 | ( | |
634 | Some(ast::Visibility { | |
635 | kind: ast::VisibilityKind::Inherited, | |
636 | .. | |
637 | }), | |
638 | None, | |
639 | ) | |
640 | | ( | |
641 | None, | |
642 | Some(ast::Visibility { | |
643 | kind: ast::VisibilityKind::Inherited, | |
644 | .. | |
645 | }), | |
646 | ) | |
647 | | (None, None) => true, | |
648 | (Some(ref a), Some(ref b)) => is_same_visibility(a, b), | |
649 | _ => false, | |
650 | } | |
651 | } | |
652 | ||
653 | fn share_prefix(&self, other: &UseTree, shared_prefix: SharedPrefix) -> bool { | |
654 | if self.path.is_empty() | |
655 | || other.path.is_empty() | |
656 | || self.attrs.is_some() | |
923072b8 | 657 | || self.contains_comment() |
f20569fa XL |
658 | || !self.same_visibility(other) |
659 | { | |
660 | false | |
661 | } else { | |
662 | match shared_prefix { | |
663 | SharedPrefix::Crate => self.path[0] == other.path[0], | |
664 | SharedPrefix::Module => { | |
665 | self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1] | |
666 | } | |
3c0e092e | 667 | SharedPrefix::One => true, |
f20569fa XL |
668 | } |
669 | } | |
670 | } | |
671 | ||
923072b8 FG |
672 | fn flatten(self, import_granularity: ImportGranularity) -> Vec<UseTree> { |
673 | if self.path.is_empty() || self.contains_comment() { | |
f20569fa XL |
674 | return vec![self]; |
675 | } | |
923072b8 FG |
676 | match &self.path.clone().last().unwrap().kind { |
677 | UseSegmentKind::List(list) => { | |
f20569fa | 678 | if list.len() == 1 && list[0].path.len() == 1 { |
923072b8 | 679 | if let UseSegmentKind::Slf(..) = list[0].path[0].kind { |
94222f64 | 680 | return vec![self]; |
f20569fa XL |
681 | }; |
682 | } | |
683 | let prefix = &self.path[..self.path.len() - 1]; | |
684 | let mut result = vec![]; | |
685 | for nested_use_tree in list { | |
923072b8 | 686 | for flattend in &mut nested_use_tree.clone().flatten(import_granularity) { |
f20569fa XL |
687 | let mut new_path = prefix.to_vec(); |
688 | new_path.append(&mut flattend.path); | |
689 | result.push(UseTree { | |
690 | path: new_path, | |
691 | span: self.span, | |
692 | list_item: None, | |
693 | visibility: self.visibility.clone(), | |
923072b8 FG |
694 | // only retain attributes for `ImportGranularity::Item` |
695 | attrs: match import_granularity { | |
696 | ImportGranularity::Item => self.attrs.clone(), | |
697 | _ => None, | |
698 | }, | |
f20569fa XL |
699 | }); |
700 | } | |
701 | } | |
702 | ||
703 | result | |
704 | } | |
705 | _ => vec![self], | |
706 | } | |
707 | } | |
708 | ||
709 | fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) { | |
710 | let mut prefix = 0; | |
711 | for (a, b) in self.path.iter().zip(other.path.iter()) { | |
5e7ed085 FG |
712 | // only discard the alias at the root of the tree |
713 | if (prefix == 0 && a.equal_except_alias(b)) || a == b { | |
f20569fa XL |
714 | prefix += 1; |
715 | } else { | |
716 | break; | |
717 | } | |
718 | } | |
719 | if let Some(new_path) = merge_rest(&self.path, &other.path, prefix, merge_by) { | |
720 | self.path = new_path; | |
721 | self.span = self.span.to(other.span); | |
722 | } | |
723 | } | |
5e7ed085 FG |
724 | |
725 | /// If this tree ends in `::self`, rewrite it to `::{self}`. | |
726 | fn nest_trailing_self(mut self) -> UseTree { | |
923072b8 FG |
727 | if let Some(UseSegment { |
728 | kind: UseSegmentKind::Slf(..), | |
729 | .. | |
730 | }) = self.path.last() | |
731 | { | |
5e7ed085 | 732 | let self_segment = self.path.pop().unwrap(); |
923072b8 FG |
733 | let version = self_segment.version; |
734 | let kind = UseSegmentKind::List(vec![UseTree::from_path(vec![self_segment], DUMMY_SP)]); | |
735 | self.path.push(UseSegment { kind, version }); | |
5e7ed085 FG |
736 | } |
737 | self | |
738 | } | |
f20569fa XL |
739 | } |
740 | ||
741 | fn merge_rest( | |
742 | a: &[UseSegment], | |
743 | b: &[UseSegment], | |
744 | mut len: usize, | |
745 | merge_by: SharedPrefix, | |
746 | ) -> Option<Vec<UseSegment>> { | |
747 | if a.len() == len && b.len() == len { | |
748 | return None; | |
749 | } | |
750 | if a.len() != len && b.len() != len { | |
923072b8 FG |
751 | let version = a[len].version; |
752 | if let UseSegmentKind::List(ref list) = a[len].kind { | |
f20569fa XL |
753 | let mut list = list.clone(); |
754 | merge_use_trees_inner( | |
755 | &mut list, | |
756 | UseTree::from_path(b[len..].to_vec(), DUMMY_SP), | |
757 | merge_by, | |
758 | ); | |
759 | let mut new_path = b[..len].to_vec(); | |
923072b8 FG |
760 | let kind = UseSegmentKind::List(list); |
761 | new_path.push(UseSegment { kind, version }); | |
f20569fa XL |
762 | return Some(new_path); |
763 | } | |
764 | } else if len == 1 { | |
3c0e092e XL |
765 | let (common, rest) = if a.len() == len { |
766 | (&a[0], &b[1..]) | |
767 | } else { | |
768 | (&b[0], &a[1..]) | |
769 | }; | |
923072b8 FG |
770 | let kind = UseSegmentKind::Slf(common.get_alias().map(ToString::to_string)); |
771 | let version = a[0].version; | |
3c0e092e | 772 | let mut list = vec![UseTree::from_path( |
923072b8 | 773 | vec![UseSegment { kind, version }], |
3c0e092e XL |
774 | DUMMY_SP, |
775 | )]; | |
776 | match rest { | |
923072b8 FG |
777 | [ |
778 | UseSegment { | |
779 | kind: UseSegmentKind::List(rest_list), | |
780 | .. | |
781 | }, | |
782 | ] => list.extend(rest_list.clone()), | |
3c0e092e XL |
783 | _ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)), |
784 | } | |
923072b8 FG |
785 | return Some(vec![ |
786 | b[0].clone(), | |
787 | UseSegment { | |
788 | kind: UseSegmentKind::List(list), | |
789 | version, | |
790 | }, | |
791 | ]); | |
f20569fa XL |
792 | } else { |
793 | len -= 1; | |
794 | } | |
795 | let mut list = vec![ | |
796 | UseTree::from_path(a[len..].to_vec(), DUMMY_SP), | |
797 | UseTree::from_path(b[len..].to_vec(), DUMMY_SP), | |
798 | ]; | |
799 | list.sort(); | |
800 | let mut new_path = b[..len].to_vec(); | |
923072b8 FG |
801 | let kind = UseSegmentKind::List(list); |
802 | let version = a[0].version; | |
803 | new_path.push(UseSegment { kind, version }); | |
f20569fa XL |
804 | Some(new_path) |
805 | } | |
806 | ||
807 | fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) { | |
3c0e092e XL |
808 | struct SimilarTree<'a> { |
809 | similarity: usize, | |
810 | path_len: usize, | |
811 | tree: &'a mut UseTree, | |
812 | } | |
813 | ||
814 | let similar_trees = trees.iter_mut().filter_map(|tree| { | |
815 | if tree.share_prefix(&use_tree, merge_by) { | |
816 | // In the case of `SharedPrefix::One`, `similarity` is used for deciding with which | |
817 | // tree `use_tree` should be merge. | |
818 | // In other cases `similarity` won't be used, so set it to `0` as a dummy value. | |
819 | let similarity = if merge_by == SharedPrefix::One { | |
820 | tree.path | |
821 | .iter() | |
822 | .zip(&use_tree.path) | |
823 | .take_while(|(a, b)| a.equal_except_alias(b)) | |
824 | .count() | |
825 | } else { | |
826 | 0 | |
827 | }; | |
828 | ||
829 | let path_len = tree.path.len(); | |
830 | Some(SimilarTree { | |
831 | similarity, | |
832 | tree, | |
833 | path_len, | |
834 | }) | |
835 | } else { | |
836 | None | |
837 | } | |
838 | }); | |
839 | ||
f20569fa | 840 | if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate { |
3c0e092e XL |
841 | if let Some(tree) = similar_trees.min_by_key(|tree| tree.path_len) { |
842 | if tree.path_len == 1 { | |
843 | return; | |
844 | } | |
845 | } | |
846 | } else if merge_by == SharedPrefix::One { | |
847 | if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.similarity) { | |
848 | if sim_tree.similarity > 0 { | |
849 | sim_tree.tree.merge(&use_tree, merge_by); | |
f20569fa XL |
850 | return; |
851 | } | |
852 | } | |
3c0e092e XL |
853 | } else if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.path_len) { |
854 | if sim_tree.path_len > 1 { | |
855 | sim_tree.tree.merge(&use_tree, merge_by); | |
f20569fa XL |
856 | return; |
857 | } | |
858 | } | |
859 | trees.push(use_tree); | |
860 | trees.sort(); | |
861 | } | |
862 | ||
923072b8 FG |
863 | impl Hash for UseTree { |
864 | fn hash<H: Hasher>(&self, state: &mut H) { | |
865 | self.path.hash(state); | |
866 | } | |
867 | } | |
868 | ||
f20569fa XL |
869 | impl PartialOrd for UseSegment { |
870 | fn partial_cmp(&self, other: &UseSegment) -> Option<Ordering> { | |
871 | Some(self.cmp(other)) | |
872 | } | |
873 | } | |
874 | impl PartialOrd for UseTree { | |
875 | fn partial_cmp(&self, other: &UseTree) -> Option<Ordering> { | |
876 | Some(self.cmp(other)) | |
877 | } | |
878 | } | |
879 | impl Ord for UseSegment { | |
880 | fn cmp(&self, other: &UseSegment) -> Ordering { | |
923072b8 | 881 | use self::UseSegmentKind::*; |
f20569fa XL |
882 | |
883 | fn is_upper_snake_case(s: &str) -> bool { | |
884 | s.chars() | |
885 | .all(|c| c.is_uppercase() || c == '_' || c.is_numeric()) | |
886 | } | |
887 | ||
923072b8 FG |
888 | match (&self.kind, &other.kind) { |
889 | (Slf(ref a), Slf(ref b)) | |
890 | | (Super(ref a), Super(ref b)) | |
891 | | (Crate(ref a), Crate(ref b)) => match (a, b) { | |
892 | (Some(sa), Some(sb)) => { | |
893 | if self.version == Version::Two { | |
894 | sa.trim_start_matches("r#").cmp(sb.trim_start_matches("r#")) | |
895 | } else { | |
896 | a.cmp(b) | |
897 | } | |
898 | } | |
899 | (_, _) => a.cmp(b), | |
900 | }, | |
901 | (Glob, Glob) => Ordering::Equal, | |
902 | (Ident(ref pia, ref aa), Ident(ref pib, ref ab)) => { | |
903 | let (ia, ib) = if self.version == Version::Two { | |
904 | (pia.trim_start_matches("r#"), pib.trim_start_matches("r#")) | |
905 | } else { | |
906 | (pia.as_str(), pib.as_str()) | |
907 | }; | |
f20569fa XL |
908 | // snake_case < CamelCase < UPPER_SNAKE_CASE |
909 | if ia.starts_with(char::is_uppercase) && ib.starts_with(char::is_lowercase) { | |
910 | return Ordering::Greater; | |
911 | } | |
912 | if ia.starts_with(char::is_lowercase) && ib.starts_with(char::is_uppercase) { | |
913 | return Ordering::Less; | |
914 | } | |
915 | if is_upper_snake_case(ia) && !is_upper_snake_case(ib) { | |
916 | return Ordering::Greater; | |
917 | } | |
918 | if !is_upper_snake_case(ia) && is_upper_snake_case(ib) { | |
919 | return Ordering::Less; | |
920 | } | |
921 | let ident_ord = ia.cmp(ib); | |
922 | if ident_ord != Ordering::Equal { | |
923 | return ident_ord; | |
924 | } | |
923072b8 FG |
925 | match (aa, ab) { |
926 | (None, Some(_)) => Ordering::Less, | |
927 | (Some(_), None) => Ordering::Greater, | |
928 | (Some(aas), Some(abs)) => { | |
929 | if self.version == Version::Two { | |
930 | aas.trim_start_matches("r#") | |
931 | .cmp(abs.trim_start_matches("r#")) | |
932 | } else { | |
933 | aas.cmp(abs) | |
934 | } | |
935 | } | |
936 | (None, None) => Ordering::Equal, | |
f20569fa | 937 | } |
f20569fa | 938 | } |
923072b8 | 939 | (List(ref a), List(ref b)) => { |
f20569fa XL |
940 | for (a, b) in a.iter().zip(b.iter()) { |
941 | let ord = a.cmp(b); | |
942 | if ord != Ordering::Equal { | |
943 | return ord; | |
944 | } | |
945 | } | |
946 | ||
947 | a.len().cmp(&b.len()) | |
948 | } | |
923072b8 FG |
949 | (Slf(_), _) => Ordering::Less, |
950 | (_, Slf(_)) => Ordering::Greater, | |
951 | (Super(_), _) => Ordering::Less, | |
952 | (_, Super(_)) => Ordering::Greater, | |
953 | (Crate(_), _) => Ordering::Less, | |
954 | (_, Crate(_)) => Ordering::Greater, | |
955 | (Ident(..), _) => Ordering::Less, | |
956 | (_, Ident(..)) => Ordering::Greater, | |
957 | (Glob, _) => Ordering::Less, | |
958 | (_, Glob) => Ordering::Greater, | |
f20569fa XL |
959 | } |
960 | } | |
961 | } | |
962 | impl Ord for UseTree { | |
963 | fn cmp(&self, other: &UseTree) -> Ordering { | |
964 | for (a, b) in self.path.iter().zip(other.path.iter()) { | |
965 | let ord = a.cmp(b); | |
966 | // The comparison without aliases is a hack to avoid situations like | |
967 | // comparing `a::b` to `a as c` - where the latter should be ordered | |
968 | // first since it is shorter. | |
969 | if ord != Ordering::Equal && a.remove_alias().cmp(&b.remove_alias()) != Ordering::Equal | |
970 | { | |
971 | return ord; | |
972 | } | |
973 | } | |
974 | ||
975 | self.path.len().cmp(&other.path.len()) | |
976 | } | |
977 | } | |
978 | ||
979 | fn rewrite_nested_use_tree( | |
980 | context: &RewriteContext<'_>, | |
981 | use_tree_list: &[UseTree], | |
982 | shape: Shape, | |
983 | ) -> Option<String> { | |
984 | let mut list_items = Vec::with_capacity(use_tree_list.len()); | |
985 | let nested_shape = match context.config.imports_indent() { | |
986 | IndentStyle::Block => shape | |
987 | .block_indent(context.config.tab_spaces()) | |
988 | .with_max_width(context.config) | |
989 | .sub_width(1)?, | |
990 | IndentStyle::Visual => shape.visual_indent(0), | |
991 | }; | |
992 | for use_tree in use_tree_list { | |
993 | if let Some(mut list_item) = use_tree.list_item.clone() { | |
994 | list_item.item = use_tree.rewrite(context, nested_shape); | |
995 | list_items.push(list_item); | |
996 | } else { | |
997 | list_items.push(ListItem::from_str(use_tree.rewrite(context, nested_shape)?)); | |
998 | } | |
999 | } | |
1000 | let has_nested_list = use_tree_list.iter().any(|use_segment| { | |
94222f64 | 1001 | use_segment.path.last().map_or(false, |last_segment| { |
923072b8 | 1002 | matches!(last_segment.kind, UseSegmentKind::List(..)) |
94222f64 | 1003 | }) |
f20569fa XL |
1004 | }); |
1005 | ||
1006 | let remaining_width = if has_nested_list { | |
1007 | 0 | |
1008 | } else { | |
1009 | shape.width.saturating_sub(2) | |
1010 | }; | |
1011 | ||
1012 | let tactic = definitive_tactic( | |
1013 | &list_items, | |
1014 | context.config.imports_layout(), | |
1015 | Separator::Comma, | |
1016 | remaining_width, | |
1017 | ); | |
1018 | ||
1019 | let ends_with_newline = context.config.imports_indent() == IndentStyle::Block | |
1020 | && tactic != DefinitiveListTactic::Horizontal; | |
1021 | let trailing_separator = if ends_with_newline { | |
1022 | context.config.trailing_comma() | |
1023 | } else { | |
1024 | SeparatorTactic::Never | |
1025 | }; | |
1026 | let fmt = ListFormatting::new(nested_shape, context.config) | |
1027 | .tactic(tactic) | |
1028 | .trailing_separator(trailing_separator) | |
1029 | .ends_with_newline(ends_with_newline) | |
1030 | .preserve_newline(true) | |
1031 | .nested(has_nested_list); | |
1032 | ||
1033 | let list_str = write_list(&list_items, &fmt)?; | |
1034 | ||
1035 | let result = if (list_str.contains('\n') || list_str.len() > remaining_width) | |
1036 | && context.config.imports_indent() == IndentStyle::Block | |
1037 | { | |
1038 | format!( | |
1039 | "{{\n{}{}\n{}}}", | |
1040 | nested_shape.indent.to_string(context.config), | |
1041 | list_str, | |
1042 | shape.indent.to_string(context.config) | |
1043 | ) | |
1044 | } else { | |
1045 | format!("{{{}}}", list_str) | |
1046 | }; | |
1047 | ||
1048 | Some(result) | |
1049 | } | |
1050 | ||
1051 | impl Rewrite for UseSegment { | |
1052 | fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> { | |
923072b8 FG |
1053 | Some(match self.kind { |
1054 | UseSegmentKind::Ident(ref ident, Some(ref rename)) => { | |
1055 | format!("{} as {}", ident, rename) | |
1056 | } | |
1057 | UseSegmentKind::Ident(ref ident, None) => ident.clone(), | |
1058 | UseSegmentKind::Slf(Some(ref rename)) => format!("self as {}", rename), | |
1059 | UseSegmentKind::Slf(None) => "self".to_owned(), | |
1060 | UseSegmentKind::Super(Some(ref rename)) => format!("super as {}", rename), | |
1061 | UseSegmentKind::Super(None) => "super".to_owned(), | |
1062 | UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {}", rename), | |
1063 | UseSegmentKind::Crate(None) => "crate".to_owned(), | |
1064 | UseSegmentKind::Glob => "*".to_owned(), | |
1065 | UseSegmentKind::List(ref use_tree_list) => rewrite_nested_use_tree( | |
f20569fa XL |
1066 | context, |
1067 | use_tree_list, | |
1068 | // 1 = "{" and "}" | |
1069 | shape.offset_left(1)?.sub_width(1)?, | |
1070 | )?, | |
1071 | }) | |
1072 | } | |
1073 | } | |
1074 | ||
1075 | impl Rewrite for UseTree { | |
1076 | // This does NOT format attributes and visibility or add a trailing `;`. | |
1077 | fn rewrite(&self, context: &RewriteContext<'_>, mut shape: Shape) -> Option<String> { | |
1078 | let mut result = String::with_capacity(256); | |
1079 | let mut iter = self.path.iter().peekable(); | |
3c0e092e | 1080 | while let Some(segment) = iter.next() { |
f20569fa XL |
1081 | let segment_str = segment.rewrite(context, shape)?; |
1082 | result.push_str(&segment_str); | |
1083 | if iter.peek().is_some() { | |
1084 | result.push_str("::"); | |
1085 | // 2 = "::" | |
1086 | shape = shape.offset_left(2 + segment_str.len())?; | |
1087 | } | |
1088 | } | |
1089 | Some(result) | |
1090 | } | |
1091 | } | |
1092 | ||
1093 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
923072b8 | 1094 | enum SharedPrefix { |
f20569fa XL |
1095 | Crate, |
1096 | Module, | |
3c0e092e | 1097 | One, |
f20569fa XL |
1098 | } |
1099 | ||
1100 | #[cfg(test)] | |
1101 | mod test { | |
1102 | use super::*; | |
1103 | use rustc_span::DUMMY_SP; | |
1104 | ||
1105 | // Parse the path part of an import. This parser is not robust and is only | |
1106 | // suitable for use in a test harness. | |
1107 | fn parse_use_tree(s: &str) -> UseTree { | |
1108 | use std::iter::Peekable; | |
1109 | use std::mem::swap; | |
1110 | use std::str::Chars; | |
1111 | ||
1112 | struct Parser<'a> { | |
1113 | input: Peekable<Chars<'a>>, | |
923072b8 | 1114 | version: Version, |
f20569fa XL |
1115 | } |
1116 | ||
1117 | impl<'a> Parser<'a> { | |
1118 | fn bump(&mut self) { | |
1119 | self.input.next().unwrap(); | |
1120 | } | |
1121 | ||
1122 | fn eat(&mut self, c: char) { | |
3c0e092e | 1123 | assert_eq!(self.input.next().unwrap(), c); |
f20569fa XL |
1124 | } |
1125 | ||
1126 | fn push_segment( | |
923072b8 | 1127 | &self, |
f20569fa XL |
1128 | result: &mut Vec<UseSegment>, |
1129 | buf: &mut String, | |
1130 | alias_buf: &mut Option<String>, | |
1131 | ) { | |
923072b8 | 1132 | let version = self.version; |
f20569fa XL |
1133 | if !buf.is_empty() { |
1134 | let mut alias = None; | |
1135 | swap(alias_buf, &mut alias); | |
1136 | ||
1137 | match buf.as_ref() { | |
1138 | "self" => { | |
923072b8 FG |
1139 | let kind = UseSegmentKind::Slf(alias); |
1140 | result.push(UseSegment { kind, version }); | |
f20569fa XL |
1141 | *buf = String::new(); |
1142 | *alias_buf = None; | |
1143 | } | |
1144 | "super" => { | |
923072b8 FG |
1145 | let kind = UseSegmentKind::Super(alias); |
1146 | result.push(UseSegment { kind, version }); | |
f20569fa XL |
1147 | *buf = String::new(); |
1148 | *alias_buf = None; | |
1149 | } | |
1150 | "crate" => { | |
923072b8 FG |
1151 | let kind = UseSegmentKind::Crate(alias); |
1152 | result.push(UseSegment { kind, version }); | |
f20569fa XL |
1153 | *buf = String::new(); |
1154 | *alias_buf = None; | |
1155 | } | |
1156 | _ => { | |
1157 | let mut name = String::new(); | |
1158 | swap(buf, &mut name); | |
923072b8 FG |
1159 | let kind = UseSegmentKind::Ident(name, alias); |
1160 | result.push(UseSegment { kind, version }); | |
f20569fa XL |
1161 | } |
1162 | } | |
1163 | } | |
1164 | } | |
1165 | ||
1166 | fn parse_in_list(&mut self) -> UseTree { | |
1167 | let mut result = vec![]; | |
1168 | let mut buf = String::new(); | |
1169 | let mut alias_buf = None; | |
1170 | while let Some(&c) = self.input.peek() { | |
1171 | match c { | |
1172 | '{' => { | |
1173 | assert!(buf.is_empty()); | |
1174 | self.bump(); | |
923072b8 FG |
1175 | let kind = UseSegmentKind::List(self.parse_list()); |
1176 | result.push(UseSegment { | |
1177 | kind, | |
1178 | version: self.version, | |
1179 | }); | |
f20569fa XL |
1180 | self.eat('}'); |
1181 | } | |
1182 | '*' => { | |
1183 | assert!(buf.is_empty()); | |
1184 | self.bump(); | |
923072b8 FG |
1185 | let kind = UseSegmentKind::Glob; |
1186 | result.push(UseSegment { | |
1187 | kind, | |
1188 | version: self.version, | |
1189 | }); | |
f20569fa XL |
1190 | } |
1191 | ':' => { | |
1192 | self.bump(); | |
1193 | self.eat(':'); | |
923072b8 | 1194 | self.push_segment(&mut result, &mut buf, &mut alias_buf); |
f20569fa XL |
1195 | } |
1196 | '}' | ',' => { | |
923072b8 | 1197 | self.push_segment(&mut result, &mut buf, &mut alias_buf); |
f20569fa XL |
1198 | return UseTree { |
1199 | path: result, | |
1200 | span: DUMMY_SP, | |
1201 | list_item: None, | |
1202 | visibility: None, | |
1203 | attrs: None, | |
1204 | }; | |
1205 | } | |
1206 | ' ' => { | |
1207 | self.bump(); | |
1208 | self.eat('a'); | |
1209 | self.eat('s'); | |
1210 | self.eat(' '); | |
1211 | alias_buf = Some(String::new()); | |
1212 | } | |
1213 | c => { | |
1214 | self.bump(); | |
1215 | if let Some(ref mut buf) = alias_buf { | |
1216 | buf.push(c); | |
1217 | } else { | |
1218 | buf.push(c); | |
1219 | } | |
1220 | } | |
1221 | } | |
1222 | } | |
923072b8 | 1223 | self.push_segment(&mut result, &mut buf, &mut alias_buf); |
f20569fa XL |
1224 | UseTree { |
1225 | path: result, | |
1226 | span: DUMMY_SP, | |
1227 | list_item: None, | |
1228 | visibility: None, | |
1229 | attrs: None, | |
1230 | } | |
1231 | } | |
1232 | ||
1233 | fn parse_list(&mut self) -> Vec<UseTree> { | |
1234 | let mut result = vec![]; | |
1235 | loop { | |
1236 | match self.input.peek().unwrap() { | |
1237 | ',' | ' ' => self.bump(), | |
1238 | '}' => { | |
1239 | return result; | |
1240 | } | |
1241 | _ => result.push(self.parse_in_list()), | |
1242 | } | |
1243 | } | |
1244 | } | |
1245 | } | |
1246 | ||
1247 | let mut parser = Parser { | |
1248 | input: s.chars().peekable(), | |
923072b8 | 1249 | version: Version::One, |
f20569fa XL |
1250 | }; |
1251 | parser.parse_in_list() | |
1252 | } | |
1253 | ||
1254 | macro_rules! parse_use_trees { | |
1255 | ($($s:expr),* $(,)*) => { | |
1256 | vec![ | |
1257 | $(parse_use_tree($s),)* | |
1258 | ] | |
1259 | } | |
1260 | } | |
1261 | ||
1262 | macro_rules! test_merge { | |
1263 | ($by:ident, [$($input:expr),* $(,)*], [$($output:expr),* $(,)*]) => { | |
1264 | assert_eq!( | |
923072b8 FG |
1265 | normalize_use_trees_with_granularity( |
1266 | parse_use_trees!($($input,)*), | |
1267 | ImportGranularity::$by, | |
1268 | ), | |
f20569fa XL |
1269 | parse_use_trees!($($output,)*), |
1270 | ); | |
1271 | } | |
1272 | } | |
1273 | ||
1274 | #[test] | |
1275 | fn test_use_tree_merge_crate() { | |
1276 | test_merge!( | |
1277 | Crate, | |
1278 | ["a::b::{c, d}", "a::b::{e, f}"], | |
1279 | ["a::b::{c, d, e, f}"] | |
1280 | ); | |
1281 | test_merge!(Crate, ["a::b::c", "a::b"], ["a::{b, b::c}"]); | |
1282 | test_merge!(Crate, ["a::b", "a::b"], ["a::b"]); | |
1283 | test_merge!(Crate, ["a", "a::b", "a::b::c"], ["a::{self, b, b::c}"]); | |
1284 | test_merge!( | |
1285 | Crate, | |
1286 | ["a", "a::b", "a::b::c", "a::b::c::d"], | |
1287 | ["a::{self, b, b::{c, c::d}}"] | |
1288 | ); | |
1289 | test_merge!( | |
1290 | Crate, | |
1291 | ["a", "a::b", "a::b::c", "a::b"], | |
1292 | ["a::{self, b, b::c}"] | |
1293 | ); | |
1294 | test_merge!( | |
1295 | Crate, | |
1296 | ["a::{b::{self, c}, d::e}", "a::d::f"], | |
1297 | ["a::{b::{self, c}, d::{e, f}}"] | |
1298 | ); | |
1299 | test_merge!( | |
1300 | Crate, | |
1301 | ["a::d::f", "a::{b::{self, c}, d::e}"], | |
1302 | ["a::{b::{self, c}, d::{e, f}}"] | |
1303 | ); | |
1304 | test_merge!( | |
1305 | Crate, | |
1306 | ["a::{c, d, b}", "a::{d, e, b, a, f}", "a::{f, g, c}"], | |
1307 | ["a::{a, b, c, d, e, f, g}"] | |
1308 | ); | |
1309 | test_merge!( | |
1310 | Crate, | |
1311 | ["a::{self}", "b::{self as foo}"], | |
1312 | ["a::{self}", "b::{self as foo}"] | |
1313 | ); | |
1314 | } | |
1315 | ||
1316 | #[test] | |
1317 | fn test_use_tree_merge_module() { | |
1318 | test_merge!( | |
1319 | Module, | |
1320 | ["foo::b", "foo::{a, c, d::e}"], | |
1321 | ["foo::{a, b, c}", "foo::d::e"] | |
1322 | ); | |
1323 | ||
1324 | test_merge!( | |
1325 | Module, | |
1326 | ["foo::{a::b, a::c, d::e, d::f}"], | |
1327 | ["foo::a::{b, c}", "foo::d::{e, f}"] | |
1328 | ); | |
1329 | } | |
1330 | ||
3c0e092e XL |
1331 | #[test] |
1332 | fn test_use_tree_merge_one() { | |
1333 | test_merge!(One, ["a", "b"], ["{a, b}"]); | |
1334 | ||
1335 | test_merge!(One, ["a::{aa, ab}", "b", "a"], ["{a::{self, aa, ab}, b}"]); | |
1336 | ||
1337 | test_merge!(One, ["a as x", "b as y"], ["{a as x, b as y}"]); | |
1338 | ||
1339 | test_merge!( | |
1340 | One, | |
1341 | ["a::{aa as xa, ab}", "b", "a"], | |
1342 | ["{a::{self, aa as xa, ab}, b}"] | |
1343 | ); | |
1344 | ||
1345 | test_merge!( | |
1346 | One, | |
1347 | ["a", "a::{aa, ab::{aba, abb}}"], | |
1348 | ["a::{self, aa, ab::{aba, abb}}"] | |
1349 | ); | |
1350 | ||
1351 | test_merge!(One, ["a", "b::{ba, *}"], ["{a, b::{ba, *}}"]); | |
1352 | ||
1353 | test_merge!(One, ["a", "b", "a::aa"], ["{a::{self, aa}, b}"]); | |
1354 | ||
1355 | test_merge!( | |
1356 | One, | |
1357 | ["a::aa::aaa", "a::ac::aca", "a::aa::*"], | |
1358 | ["a::{aa::{aaa, *}, ac::aca}"] | |
1359 | ); | |
1360 | ||
1361 | test_merge!( | |
1362 | One, | |
1363 | ["a", "b::{ba, bb}", "a::{aa::*, ab::aba}"], | |
1364 | ["{a::{self, aa::*, ab::aba}, b::{ba, bb}}"] | |
1365 | ); | |
1366 | ||
1367 | test_merge!( | |
1368 | One, | |
1369 | ["b", "a::ac::{aca, acb}", "a::{aa::*, ab}"], | |
1370 | ["{a::{aa::*, ab, ac::{aca, acb}}, b}"] | |
1371 | ); | |
1372 | } | |
1373 | ||
f20569fa XL |
1374 | #[test] |
1375 | fn test_flatten_use_trees() { | |
1376 | assert_eq!( | |
923072b8 FG |
1377 | flatten_use_trees( |
1378 | parse_use_trees!["foo::{a::{b, c}, d::e}"], | |
1379 | ImportGranularity::Item | |
1380 | ), | |
f20569fa XL |
1381 | parse_use_trees!["foo::a::b", "foo::a::c", "foo::d::e"] |
1382 | ); | |
1383 | ||
1384 | assert_eq!( | |
923072b8 FG |
1385 | flatten_use_trees( |
1386 | parse_use_trees!["foo::{self, a, b::{c, d}, e::*}"], | |
1387 | ImportGranularity::Item | |
1388 | ), | |
f20569fa XL |
1389 | parse_use_trees![ |
1390 | "foo::{self}", | |
1391 | "foo::a", | |
1392 | "foo::b::c", | |
1393 | "foo::b::d", | |
1394 | "foo::e::*" | |
1395 | ] | |
1396 | ); | |
1397 | } | |
1398 | ||
1399 | #[test] | |
1400 | fn test_use_tree_flatten() { | |
1401 | assert_eq!( | |
923072b8 | 1402 | parse_use_tree("a::b::{c, d, e, f}").flatten(ImportGranularity::Item), |
f20569fa XL |
1403 | parse_use_trees!("a::b::c", "a::b::d", "a::b::e", "a::b::f",) |
1404 | ); | |
1405 | ||
1406 | assert_eq!( | |
923072b8 FG |
1407 | parse_use_tree("a::b::{c::{d, e, f}, g, h::{i, j, k}}") |
1408 | .flatten(ImportGranularity::Item), | |
f20569fa XL |
1409 | parse_use_trees![ |
1410 | "a::b::c::d", | |
1411 | "a::b::c::e", | |
1412 | "a::b::c::f", | |
1413 | "a::b::g", | |
1414 | "a::b::h::i", | |
1415 | "a::b::h::j", | |
1416 | "a::b::h::k", | |
1417 | ] | |
1418 | ); | |
1419 | } | |
1420 | ||
1421 | #[test] | |
1422 | fn test_use_tree_normalize() { | |
1423 | assert_eq!(parse_use_tree("a::self").normalize(), parse_use_tree("a")); | |
1424 | assert_eq!( | |
1425 | parse_use_tree("a::self as foo").normalize(), | |
1426 | parse_use_tree("a as foo") | |
1427 | ); | |
1428 | assert_eq!( | |
1429 | parse_use_tree("a::{self}").normalize(), | |
1430 | parse_use_tree("a::{self}") | |
1431 | ); | |
1432 | assert_eq!(parse_use_tree("a::{b}").normalize(), parse_use_tree("a::b")); | |
1433 | assert_eq!( | |
1434 | parse_use_tree("a::{b, c::self}").normalize(), | |
1435 | parse_use_tree("a::{b, c}") | |
1436 | ); | |
1437 | assert_eq!( | |
1438 | parse_use_tree("a::{b as bar, c::self}").normalize(), | |
1439 | parse_use_tree("a::{b as bar, c}") | |
1440 | ); | |
1441 | } | |
1442 | ||
1443 | #[test] | |
1444 | fn test_use_tree_ord() { | |
1445 | assert!(parse_use_tree("a").normalize() < parse_use_tree("aa").normalize()); | |
1446 | assert!(parse_use_tree("a").normalize() < parse_use_tree("a::a").normalize()); | |
1447 | assert!(parse_use_tree("a").normalize() < parse_use_tree("*").normalize()); | |
1448 | assert!(parse_use_tree("a").normalize() < parse_use_tree("{a, b}").normalize()); | |
1449 | assert!(parse_use_tree("*").normalize() < parse_use_tree("{a, b}").normalize()); | |
1450 | ||
1451 | assert!( | |
1452 | parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, dddddddd}").normalize() | |
1453 | < parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, ddddddddd}").normalize() | |
1454 | ); | |
1455 | assert!( | |
1456 | parse_use_tree("serde::de::{Deserialize}").normalize() | |
1457 | < parse_use_tree("serde_json").normalize() | |
1458 | ); | |
1459 | assert!(parse_use_tree("a::b::c").normalize() < parse_use_tree("a::b::*").normalize()); | |
1460 | assert!( | |
1461 | parse_use_tree("foo::{Bar, Baz}").normalize() | |
1462 | < parse_use_tree("{Bar, Baz}").normalize() | |
1463 | ); | |
1464 | ||
1465 | assert!( | |
1466 | parse_use_tree("foo::{qux as bar}").normalize() | |
1467 | < parse_use_tree("foo::{self as bar}").normalize() | |
1468 | ); | |
1469 | assert!( | |
1470 | parse_use_tree("foo::{qux as bar}").normalize() | |
1471 | < parse_use_tree("foo::{baz, qux as bar}").normalize() | |
1472 | ); | |
1473 | assert!( | |
1474 | parse_use_tree("foo::{self as bar, baz}").normalize() | |
1475 | < parse_use_tree("foo::{baz, qux as bar}").normalize() | |
1476 | ); | |
1477 | ||
1478 | assert!(parse_use_tree("foo").normalize() < parse_use_tree("Foo").normalize()); | |
1479 | assert!(parse_use_tree("foo").normalize() < parse_use_tree("foo::Bar").normalize()); | |
1480 | ||
1481 | assert!( | |
1482 | parse_use_tree("std::cmp::{d, c, b, a}").normalize() | |
1483 | < parse_use_tree("std::cmp::{b, e, g, f}").normalize() | |
1484 | ); | |
1485 | } | |
5e7ed085 FG |
1486 | |
1487 | #[test] | |
1488 | fn test_use_tree_nest_trailing_self() { | |
1489 | assert_eq!( | |
1490 | parse_use_tree("a::b::self").nest_trailing_self(), | |
1491 | parse_use_tree("a::b::{self}") | |
1492 | ); | |
1493 | assert_eq!( | |
1494 | parse_use_tree("a::b::c").nest_trailing_self(), | |
1495 | parse_use_tree("a::b::c") | |
1496 | ); | |
1497 | assert_eq!( | |
1498 | parse_use_tree("a::b::{c, d}").nest_trailing_self(), | |
1499 | parse_use_tree("a::b::{c, d}") | |
1500 | ); | |
1501 | assert_eq!( | |
1502 | parse_use_tree("a::b::{self, c}").nest_trailing_self(), | |
1503 | parse_use_tree("a::b::{self, c}") | |
1504 | ); | |
1505 | } | |
f20569fa | 1506 | } |