1use std::cmp::Ordering;
3
4use itertools::{EitherOrBoth, Itertools};
5use parser::T;
6use syntax::{
7 ToSmolStr,
8 ast::{
9 self, AstNode, HasAttrs, HasName, HasVisibility, PathSegmentKind,
10 syntax_factory::SyntaxFactory,
11 },
12 syntax_editor::{Position, SyntaxEditor},
13};
14
15use crate::syntax_helpers::node_ext::vis_eq;
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
19pub enum MergeBehavior {
20 Crate,
22 Module,
24 One,
27}
28
29impl MergeBehavior {
30 fn is_tree_allowed(&self, tree: &ast::UseTree) -> bool {
31 match self {
32 MergeBehavior::Crate | MergeBehavior::One => true,
33 MergeBehavior::Module => {
35 tree.use_tree_list().is_none() && tree.path().map(path_len) <= Some(1)
36 }
37 }
38 }
39}
40
41pub fn try_merge_imports(
43 make: &SyntaxFactory,
44 lhs: &ast::Use,
45 rhs: &ast::Use,
46 merge_behavior: MergeBehavior,
47) -> Option<ast::Use> {
48 if !eq_visibility(lhs.visibility(), rhs.visibility()) {
50 return None;
51 }
52 if !eq_attrs(lhs.attrs(), rhs.attrs()) {
53 return None;
54 }
55
56 let lhs_tree = lhs.use_tree()?;
57 let rhs_tree = rhs.use_tree()?;
58 let merged_tree = try_merge_trees_with_factory(lhs_tree, rhs_tree, merge_behavior, make)?;
59
60 let use_tree = try_normalize_use_tree(merged_tree.clone(), merge_behavior.into(), make)
62 .unwrap_or(merged_tree);
63
64 make_use_with_tree(lhs, use_tree)
65}
66
67pub fn try_merge_trees(
69 make: &SyntaxFactory,
70 lhs: &ast::UseTree,
71 rhs: &ast::UseTree,
72 merge: MergeBehavior,
73) -> Option<ast::UseTree> {
74 let merged = try_merge_trees_with_factory(lhs.clone(), rhs.clone(), merge, make)?;
75
76 Some(try_normalize_use_tree(merged.clone(), merge.into(), make).unwrap_or(merged))
78}
79
80fn try_merge_trees_with_factory(
81 mut lhs: ast::UseTree,
82 mut rhs: ast::UseTree,
83 merge: MergeBehavior,
84 make: &SyntaxFactory,
85) -> Option<ast::UseTree> {
86 if merge == MergeBehavior::One {
87 lhs = wrap_in_tree_list(&lhs, make).unwrap_or(lhs);
88 rhs = wrap_in_tree_list(&rhs, make).unwrap_or(rhs);
89 } else {
90 let lhs_path = lhs.path()?;
91 let rhs_path = rhs.path()?;
92
93 let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
94 if lhs.is_simple_path()
95 && rhs.is_simple_path()
96 && lhs_path == lhs_prefix
97 && rhs_path == rhs_prefix
98 {
99 let lhs_name = lhs.rename().and_then(|lhs_name| lhs_name.name());
102 let rhs_name = rhs.rename().and_then(|rhs_name| rhs_name.name());
103 if lhs_name.as_ref().map(|name| name.text())
104 != rhs_name.as_ref().map(|name| name.text())
105 {
106 return None;
107 }
108
109 return Some(rhs);
110 } else {
111 lhs = split_prefix(&lhs, &lhs_prefix, make)?;
112 rhs = split_prefix(&rhs, &rhs_prefix, make)?;
113 }
114 }
115 recursive_merge(lhs, rhs, merge, make)
116}
117
118#[must_use]
120fn recursive_merge(
121 lhs: ast::UseTree,
122 rhs: ast::UseTree,
123 merge: MergeBehavior,
124 make: &SyntaxFactory,
125) -> Option<ast::UseTree> {
126 let mut use_trees: Vec<ast::UseTree> = lhs
127 .use_tree_list()?
128 .use_trees()
129 .map(|tree| merge.is_tree_allowed(&tree).then_some(tree))
132 .collect::<Option<_>>()?;
133
134 use_trees.sort_unstable_by(use_tree_cmp);
137
138 for rhs_t in rhs.use_tree_list()?.use_trees() {
139 if !merge.is_tree_allowed(&rhs_t) {
140 return None;
141 }
142
143 match use_trees.binary_search_by(|lhs_t| use_tree_cmp_bin_search(lhs_t, &rhs_t)) {
144 Ok(idx) => {
145 let mut lhs_t = use_trees[idx].clone();
146 let lhs_path = lhs_t.path()?;
147 let rhs_path = rhs_t.path()?;
148 let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;
149
150 if lhs_prefix == lhs_path && rhs_prefix == rhs_path {
151 let tree_is_self = |tree: &ast::UseTree| {
152 tree.path().as_ref().map(path_is_self).unwrap_or(false)
153 };
154 let tree_contains_self = |tree: &ast::UseTree| {
159 tree.use_tree_list()
160 .map(|tree_list| tree_list.use_trees().any(|it| tree_is_self(&it)))
161 .or_else(|| tree.star_token().map(|_| false))
164 };
165
166 if lhs_t.rename().and_then(|x| x.underscore_token()).is_some() {
167 use_trees[idx] = rhs_t;
168 continue;
169 }
170
171 match (tree_contains_self(&lhs_t), tree_contains_self(&rhs_t)) {
172 (Some(true), None) => {
173 lhs_t = remove_subtree_if_only_self(lhs_t, make)?;
174 use_trees[idx] = lhs_t;
175 continue;
176 }
177 (None, Some(true)) => {
178 lhs_t = rhs_t;
179 lhs_t = remove_subtree_if_only_self(lhs_t, make)?;
180 use_trees[idx] = lhs_t;
181 continue;
182 }
183 _ => (),
184 }
185
186 if lhs_t.is_simple_path() && rhs_t.is_simple_path() {
187 continue;
188 }
189 }
190
191 lhs_t = split_prefix(&lhs_t, &lhs_prefix, make)?;
192 let rhs_t = split_prefix(&rhs_t, &rhs_prefix, make)?;
193 lhs_t = recursive_merge(lhs_t, rhs_t, merge, make)?;
194 use_trees[idx] = lhs_t;
195 }
196 Err(_)
197 if merge == MergeBehavior::Module
198 && !use_trees.is_empty()
199 && rhs_t.use_tree_list().is_some() =>
200 {
201 return None;
202 }
203 Err(insert_idx) => {
204 use_trees.insert(insert_idx, rhs_t);
205 }
206 }
207 }
208
209 with_use_tree_list(&lhs, use_trees, make)
210}
211
212#[derive(Copy, Clone, Debug, PartialEq, Eq)]
214pub enum NormalizationStyle {
215 Default,
222 One,
229}
230
231impl From<MergeBehavior> for NormalizationStyle {
232 fn from(mb: MergeBehavior) -> Self {
233 match mb {
234 MergeBehavior::One => NormalizationStyle::One,
235 _ => NormalizationStyle::Default,
236 }
237 }
238}
239
240pub fn try_normalize_import(
260 make: &SyntaxFactory,
261 use_item: &ast::Use,
262 style: NormalizationStyle,
263) -> Option<ast::Use> {
264 let use_tree = try_normalize_use_tree(use_item.use_tree()?, style, make)?;
265
266 make_use_with_tree(use_item, use_tree)
267}
268
269fn try_normalize_use_tree(
270 use_tree: ast::UseTree,
271 style: NormalizationStyle,
272 make: &SyntaxFactory,
273) -> Option<ast::UseTree> {
274 if style == NormalizationStyle::One {
275 let mut use_tree = use_tree;
276 let mut modified = false;
277 if let Some(wrapped) = wrap_in_tree_list(&use_tree, make) {
278 use_tree = wrapped;
279 modified = true;
280 }
281 if let Some(normalized) = recursive_normalize(use_tree.clone(), style, make) {
282 use_tree = normalized;
283 modified = true;
284 }
285 return modified.then_some(use_tree);
286 }
287
288 recursive_normalize(use_tree, NormalizationStyle::Default, make)
289}
290
291fn recursive_normalize(
293 use_tree: ast::UseTree,
294 style: NormalizationStyle,
295 make: &SyntaxFactory,
296) -> Option<ast::UseTree> {
297 let use_tree_list = use_tree.use_tree_list()?;
298 let mut subtrees = use_tree_list.use_trees().collect::<Vec<_>>();
299 if subtrees.len() == 1 {
300 if style == NormalizationStyle::One {
301 let subtree = subtrees.pop()?;
302 let normalized = recursive_normalize(subtree, NormalizationStyle::Default, make)?;
303 return with_use_tree_list(&use_tree, vec![normalized], make);
304 }
305
306 let merged = merge_single_subtree_into_parent_tree(use_tree, make)?;
307 return Some(recursive_normalize(merged.clone(), style, make).unwrap_or(merged));
308 }
309
310 let mut modified = false;
311 let mut new_use_tree_list = Vec::new();
312 for subtree in subtrees {
313 if one_style_tree_list(&subtree).is_some() {
314 let mut elements = Vec::new();
315 flatten_one_style_tree(subtree, &mut elements, &mut modified, make);
316 new_use_tree_list.extend(elements);
317 modified = true;
318 } else if let Some(normalized) =
319 recursive_normalize(subtree.clone(), NormalizationStyle::Default, make)
320 {
321 new_use_tree_list.push(normalized);
322 modified = true;
323 } else {
324 new_use_tree_list.push(subtree);
325 }
326 }
327
328 let mut use_tree =
329 if modified { with_use_tree_list(&use_tree, new_use_tree_list, make)? } else { use_tree };
330
331 let mut use_tree_list = use_tree.use_tree_list()?.use_trees().collect::<Vec<_>>();
332 let mut anchor_idx = 0;
333 let mut merged_any = false;
334 while anchor_idx < use_tree_list.len() {
335 let mut candidate_idx = anchor_idx + 1;
336 while candidate_idx < use_tree_list.len() {
337 if let Some(mut merged) = try_merge_trees_with_factory(
338 use_tree_list[anchor_idx].clone(),
339 use_tree_list[candidate_idx].clone(),
340 MergeBehavior::Crate,
341 make,
342 ) {
343 if let Some(normalized) =
344 recursive_normalize(merged.clone(), NormalizationStyle::Default, make)
345 {
346 merged = normalized;
347 }
348
349 use_tree_list[anchor_idx] = merged;
350 use_tree_list.remove(candidate_idx);
351 merged_any = true;
352 } else {
353 candidate_idx += 1;
354 }
355 }
356
357 anchor_idx += 1;
358 }
359 if merged_any {
360 use_tree = with_use_tree_list(&use_tree, use_tree_list, make)?;
361 modified = true;
362 }
363
364 if style != NormalizationStyle::One {
365 let subtrees = use_tree.use_tree_list()?.use_trees().collect::<Vec<_>>();
366 if subtrees.len() == 1
367 && let Some(merged) = merge_single_subtree_into_parent_tree(use_tree.clone(), make)
368 {
369 use_tree = merged;
370 modified = true;
371 }
372 }
373
374 if let Some(list) = use_tree.use_tree_list() {
375 let mut use_tree_list = list.use_trees().collect::<Vec<_>>();
376 if use_tree_list
377 .windows(2)
378 .any(|trees| use_tree_cmp_bin_search(&trees[0], &trees[1]).is_gt())
379 {
380 use_tree_list.sort_unstable_by(use_tree_cmp_bin_search);
381 use_tree = with_use_tree_list(&use_tree, use_tree_list, make)?;
382 modified = true;
383 }
384 }
385
386 modified.then_some(use_tree)
387}
388
389fn flatten_one_style_tree(
390 subtree: ast::UseTree,
391 elements: &mut Vec<ast::UseTree>,
392 modified: &mut bool,
393 make: &SyntaxFactory,
394) {
395 let Some(one_tree_list) = one_style_tree_list(&subtree) else { return };
396 let mut one_tree_list_iter = one_tree_list.use_trees();
397 let mut prev_skipped = Vec::new();
398 loop {
399 let mut prev_skipped_iter = prev_skipped.into_iter();
400 let mut curr_skipped = Vec::new();
401
402 while let Some(sub_sub_tree) =
403 one_tree_list_iter.next().or_else(|| prev_skipped_iter.next())
404 {
405 if let Some(sub_one_tree_list) = one_style_tree_list(&sub_sub_tree) {
406 curr_skipped.extend(sub_one_tree_list.use_trees());
407 } else if let Some(normalized) =
408 recursive_normalize(sub_sub_tree.clone(), NormalizationStyle::Default, make)
409 {
410 *modified = true;
411 elements.push(normalized);
412 } else {
413 elements.push(sub_sub_tree);
414 }
415 }
416
417 if curr_skipped.is_empty() {
418 break;
419 }
420 prev_skipped = curr_skipped;
421 }
422}
423
424fn merge_single_subtree_into_parent_tree(
425 use_tree: ast::UseTree,
426 make: &SyntaxFactory,
427) -> Option<ast::UseTree> {
428 let single_subtree = get_single_subtree(&use_tree)?;
429 let subtree_is_only_self = single_subtree.path().as_ref().is_some_and(path_is_self);
430
431 let merged_path = match (use_tree.path(), single_subtree.path()) {
432 _ if subtree_is_only_self => None,
433 (None, None) => None,
434 (Some(outer), None) => Some(outer),
435 (None, Some(inner)) => Some(inner),
436 (Some(outer), Some(inner)) => Some(make.path_concat(outer, inner)),
437 };
438
439 let list = single_subtree.use_tree_list();
440 let list_is_none = list.is_none();
441 let star = single_subtree.star_token().is_some();
442 if merged_path.is_some() || list.is_some() || star {
443 let rename = (!star && list_is_none).then(|| single_subtree.rename()).flatten();
444 make_use_tree_from_parts(make, merged_path, list, rename, star)
445 } else {
446 None
447 }
448}
449
450fn one_style_tree_list(subtree: &ast::UseTree) -> Option<ast::UseTreeList> {
451 (subtree.path().is_none() && subtree.star_token().is_none() && subtree.rename().is_none())
452 .then(|| subtree.use_tree_list())
453 .flatten()
454}
455
456fn remove_subtree_if_only_self(
457 use_tree: ast::UseTree,
458 make: &SyntaxFactory,
459) -> Option<ast::UseTree> {
460 let Some(single_subtree) = get_single_subtree(&use_tree) else {
461 return Some(use_tree);
462 };
463 match (use_tree.path(), single_subtree.path()) {
464 (Some(path), Some(inner)) if path_is_self(&inner) => {
465 Some(make.use_tree(path, None, use_tree.rename(), false))
466 }
467 _ => Some(use_tree),
468 }
469}
470
471pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
473 let mut res = None;
474 let mut lhs_curr = lhs.first_qualifier_or_self();
475 let mut rhs_curr = rhs.first_qualifier_or_self();
476 loop {
477 match (lhs_curr.segment(), rhs_curr.segment()) {
478 (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (),
479 _ => break res,
480 }
481 res = Some((lhs_curr.clone(), rhs_curr.clone()));
482
483 match lhs_curr.parent_path().zip(rhs_curr.parent_path()) {
484 Some((lhs, rhs)) => {
485 lhs_curr = lhs;
486 rhs_curr = rhs;
487 }
488 _ => break res,
489 }
490 }
491}
492
493fn use_tree_cmp_bin_search(lhs: &ast::UseTree, rhs: &ast::UseTree) -> Ordering {
495 let lhs_is_simple_path = lhs.is_simple_path() && lhs.rename().is_none();
496 let rhs_is_simple_path = rhs.is_simple_path() && rhs.rename().is_none();
497 let lhs_segment = lhs.path().and_then(|path| path.first_segment());
498 let rhs_segment = rhs.path().and_then(|path| path.first_segment());
499 match (lhs_segment, rhs_segment) {
500 (None, None) => match (lhs_is_simple_path, rhs_is_simple_path) {
501 (true, true) => Ordering::Equal,
502 (true, false) => Ordering::Less,
503 (false, true) => Ordering::Greater,
504 (false, false) => use_tree_cmp_by_tree_list_glob_or_alias(lhs, rhs, false),
505 },
506 (Some(_), None) if !rhs_is_simple_path => Ordering::Less,
507 (Some(_), None) => Ordering::Greater,
508 (None, Some(_)) if !lhs_is_simple_path => Ordering::Greater,
509 (None, Some(_)) => Ordering::Less,
510 (Some(a), Some(b)) => path_segment_cmp(&a, &b),
511 }
512}
513
514pub(super) fn use_tree_cmp(a: &ast::UseTree, b: &ast::UseTree) -> Ordering {
522 let a_is_simple_path = a.is_simple_path() && a.rename().is_none();
523 let b_is_simple_path = b.is_simple_path() && b.rename().is_none();
524 match (a.path(), b.path()) {
525 (None, None) => match (a_is_simple_path, b_is_simple_path) {
526 (true, true) => Ordering::Equal,
527 (true, false) => Ordering::Less,
528 (false, true) => Ordering::Greater,
529 (false, false) => use_tree_cmp_by_tree_list_glob_or_alias(a, b, true),
530 },
531 (Some(_), None) if !b_is_simple_path => Ordering::Less,
532 (Some(_), None) => Ordering::Greater,
533 (None, Some(_)) if !a_is_simple_path => Ordering::Greater,
534 (None, Some(_)) => Ordering::Less,
535 (Some(a_path), Some(b_path)) => {
536 a_path
539 .segments()
540 .zip_longest(b_path.segments())
541 .find_map(|zipped| match zipped {
542 EitherOrBoth::Both(a_segment, b_segment) => {
543 match path_segment_cmp(&a_segment, &b_segment) {
544 Ordering::Equal => None,
545 ord => Some(ord),
546 }
547 }
548 EitherOrBoth::Left(_) if b_is_simple_path => Some(Ordering::Greater),
549 EitherOrBoth::Left(_) => Some(Ordering::Less),
550 EitherOrBoth::Right(_) if a_is_simple_path => Some(Ordering::Less),
551 EitherOrBoth::Right(_) => Some(Ordering::Greater),
552 })
553 .unwrap_or_else(|| use_tree_cmp_by_tree_list_glob_or_alias(a, b, true))
554 }
555 }
556}
557
558fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
559 match (a.kind(), b.kind()) {
560 (None, None) => Ordering::Equal,
561 (Some(_), None) => Ordering::Greater,
562 (None, Some(_)) => Ordering::Less,
563 (Some(PathSegmentKind::SelfKw), Some(PathSegmentKind::SelfKw)) => Ordering::Equal,
565 (Some(PathSegmentKind::SelfKw), _) => Ordering::Less,
566 (_, Some(PathSegmentKind::SelfKw)) => Ordering::Greater,
567 (Some(PathSegmentKind::SuperKw), Some(PathSegmentKind::SuperKw)) => Ordering::Equal,
569 (Some(PathSegmentKind::SuperKw), _) => Ordering::Less,
570 (_, Some(PathSegmentKind::SuperKw)) => Ordering::Greater,
571 (Some(PathSegmentKind::CrateKw), Some(PathSegmentKind::CrateKw)) => Ordering::Equal,
573 (Some(PathSegmentKind::CrateKw), _) => Ordering::Less,
574 (_, Some(PathSegmentKind::CrateKw)) => Ordering::Greater,
575 _ => {
577 match (
578 a.name_ref().as_ref().map(ast::NameRef::text),
579 b.name_ref().as_ref().map(ast::NameRef::text),
580 ) {
581 (None, None) => Ordering::Equal,
582 (Some(_), None) => Ordering::Greater,
583 (None, Some(_)) => Ordering::Less,
584 (Some(a_name), Some(b_name)) => {
585 let a_text = a_name.as_str().trim_start_matches("r#");
586 let b_text = b_name.as_str().trim_start_matches("r#");
587 version_sort::version_sort(a_text, b_text)
588 }
589 }
590 }
591 }
592}
593
594fn use_tree_cmp_by_tree_list_glob_or_alias(
602 a: &ast::UseTree,
603 b: &ast::UseTree,
604 strict: bool,
605) -> Ordering {
606 let cmp_by_glob_or_alias = || match (a.star_token().is_some(), b.star_token().is_some()) {
607 (true, false) => Ordering::Greater,
608 (false, true) => Ordering::Less,
609 _ => match (a.rename(), b.rename()) {
610 (None, None) => Ordering::Equal,
611 (Some(_), None) => Ordering::Greater,
612 (None, Some(_)) => Ordering::Less,
613 (Some(a_rename), Some(b_rename)) => a_rename
614 .name()
615 .as_ref()
616 .map(ast::Name::text)
617 .as_ref()
618 .map_or("_", |a_name| a_name.as_str().trim_start_matches("r#"))
619 .cmp(
620 b_rename
621 .name()
622 .as_ref()
623 .map(ast::Name::text)
624 .as_ref()
625 .map_or("_", |b_name| b_name.as_str().trim_start_matches("r#")),
626 ),
627 },
628 };
629
630 match (a.use_tree_list(), b.use_tree_list()) {
631 (Some(_), None) => Ordering::Greater,
632 (None, Some(_)) => Ordering::Less,
633 (Some(a_list), Some(b_list)) if strict => a_list
634 .use_trees()
635 .zip_longest(b_list.use_trees())
636 .find_map(|zipped| match zipped {
637 EitherOrBoth::Both(a_tree, b_tree) => match use_tree_cmp(&a_tree, &b_tree) {
638 Ordering::Equal => None,
639 ord => Some(ord),
640 },
641 EitherOrBoth::Left(_) => Some(Ordering::Greater),
642 EitherOrBoth::Right(_) => Some(Ordering::Less),
643 })
644 .unwrap_or_else(cmp_by_glob_or_alias),
645 _ => cmp_by_glob_or_alias(),
646 }
647}
648
649pub fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool {
650 match (vis0, vis1) {
651 (None, None) => true,
652 (Some(vis0), Some(vis1)) => vis_eq(&vis0, &vis1),
653 _ => false,
654 }
655}
656
657pub fn eq_attrs(
658 attrs0: impl Iterator<Item = ast::Attr>,
659 attrs1: impl Iterator<Item = ast::Attr>,
660) -> bool {
661 let mut attrs0: Vec<_> = attrs0.map(|attr| attr.syntax().text().to_smolstr()).collect();
662 let mut attrs1: Vec<_> = attrs1.map(|attr| attr.syntax().text().to_smolstr()).collect();
663 attrs0.sort_unstable();
664 attrs1.sort_unstable();
665
666 attrs0 == attrs1
667}
668
669fn path_is_self(path: &ast::Path) -> bool {
670 path.segment().and_then(|seg| seg.self_token()).is_some() && path.qualifier().is_none()
671}
672
673fn path_len(path: ast::Path) -> usize {
674 path.segments().count()
675}
676
677fn get_single_subtree(use_tree: &ast::UseTree) -> Option<ast::UseTree> {
678 use_tree
679 .use_tree_list()
680 .and_then(|tree_list| tree_list.use_trees().collect_tuple())
681 .map(|(single_subtree,)| single_subtree)
682}
683
684fn make_use_with_tree(original: &ast::Use, use_tree: ast::UseTree) -> Option<ast::Use> {
685 let (editor, use_item) = SyntaxEditor::with_ast_node(original);
686 let original_tree = use_item.use_tree()?;
687 editor.replace(original_tree.syntax(), use_tree.syntax());
688 let edit = editor.finish();
689 ast::Use::cast(edit.new_root().clone())
690}
691
692fn make_use_tree_list(
693 make: &SyntaxFactory,
694 use_trees: Vec<ast::UseTree>,
695 style_source: Option<&ast::UseTreeList>,
696) -> Option<ast::UseTreeList> {
697 let use_tree_list = make.use_tree_list(use_trees);
698 let Some(style_source) = style_source else {
699 return Some(use_tree_list);
700 };
701
702 let source_l_curly = style_source.l_curly_token()?;
703 let source_r_curly = style_source.r_curly_token()?;
704
705 let leading_ws = source_l_curly.next_token().filter(|token| token.kind().is_trivia());
706
707 let trailing_ws = source_r_curly.prev_token().filter(|token| token.kind().is_trivia());
708
709 let source_trailing_token = trailing_ws
710 .as_ref()
711 .and_then(|token| token.prev_token())
712 .or_else(|| source_r_curly.prev_token());
713
714 let source_has_trailing_comma =
715 source_trailing_token.is_some_and(|token| token.kind() == T![,]);
716
717 let (editor, use_tree_list) = SyntaxEditor::with_ast_node(&use_tree_list);
718 let make = editor.make();
719
720 if let Some(leading_ws) = leading_ws {
721 editor.insert(
722 Position::after(use_tree_list.l_curly_token()?),
723 make.whitespace(leading_ws.text()),
724 );
725 }
726
727 let r_curly = use_tree_list.r_curly_token()?;
728
729 let generated_has_trailing_comma = r_curly
730 .prev_token()
731 .and_then(|token| if token.kind().is_trivia() { token.prev_token() } else { Some(token) })
732 .is_some_and(|token| token.kind() == T![,]);
733
734 let mut trailing = Vec::new();
735
736 if source_has_trailing_comma
737 && !generated_has_trailing_comma
738 && use_tree_list.use_trees().next().is_some()
739 {
740 trailing.push(make.token(T![,]).into());
741 }
742
743 if let Some(trailing_ws) = trailing_ws {
744 trailing.push(make.whitespace(trailing_ws.text()).into());
745 }
746
747 if !trailing.is_empty() {
748 editor.insert_all(Position::before(r_curly), trailing);
749 }
750
751 let edit = editor.finish();
752 ast::UseTreeList::cast(edit.new_root().clone())
753}
754
755fn make_use_tree_from_list(make: &SyntaxFactory, list: ast::UseTreeList) -> Option<ast::UseTree> {
756 let placeholder = make.use_tree_glob();
757 let (editor, use_tree) = SyntaxEditor::with_ast_node(&placeholder);
758 let first_child = use_tree.syntax().first_child_or_token()?;
759 let last_child = use_tree.syntax().last_child_or_token()?;
760 editor.replace_all(first_child..=last_child, vec![list.syntax().clone().into()]);
761 let edit = editor.finish();
762 ast::UseTree::cast(edit.new_root().clone())
763}
764
765fn make_use_tree_from_parts(
766 make: &SyntaxFactory,
767 path: Option<ast::Path>,
768 list: Option<ast::UseTreeList>,
769 rename: Option<ast::Rename>,
770 star: bool,
771) -> Option<ast::UseTree> {
772 match (path, list, star) {
773 (Some(path), list, star) => Some(make.use_tree(path, list, rename, star)),
774 (None, Some(list), false) if rename.is_none() => make_use_tree_from_list(make, list),
775 (None, None, true) if rename.is_none() => Some(make.use_tree_glob()),
776 (None, None, false) if rename.is_none() => None,
777 _ => None,
778 }
779}
780
781fn with_use_tree_list(
782 use_tree: &ast::UseTree,
783 use_trees: Vec<ast::UseTree>,
784 make: &SyntaxFactory,
785) -> Option<ast::UseTree> {
786 let list = make_use_tree_list(make, use_trees, use_tree.use_tree_list().as_ref())?;
787 make_use_tree_from_parts(
788 make,
789 use_tree.path(),
790 Some(list),
791 use_tree.rename(),
792 use_tree.star_token().is_some(),
793 )
794}
795
796pub(crate) fn wrap_in_tree_list(
797 use_tree: &ast::UseTree,
798 make: &SyntaxFactory,
799) -> Option<ast::UseTree> {
800 if use_tree.path().is_none()
801 && use_tree.use_tree_list().is_some()
802 && use_tree.rename().is_none()
803 && use_tree.star_token().is_none()
804 {
805 return None;
806 }
807
808 let list = make_use_tree_list(make, vec![use_tree.clone()], None)?;
809 make_use_tree_from_list(make, list)
810}
811
812fn split_prefix(
813 use_tree: &ast::UseTree,
814 prefix: &ast::Path,
815 make: &SyntaxFactory,
816) -> Option<ast::UseTree> {
817 let path = use_tree.path()?;
818 if path == *prefix && use_tree.use_tree_list().is_some() {
819 return Some(use_tree.clone());
820 }
821
822 let suffix = if path == *prefix {
823 if use_tree.star_token().is_some() {
824 make.use_tree_glob()
825 } else {
826 let self_path = make.path_unqualified(make.path_segment_self());
827 make.use_tree(self_path, None, use_tree.rename(), false)
828 }
829 } else {
830 let suffix_segments = path.segments().skip(prefix.segments().count());
831 let suffix_path = make.path_from_segments(suffix_segments, false);
832 make.use_tree(
833 suffix_path,
834 use_tree.use_tree_list(),
835 use_tree.rename(),
836 use_tree.star_token().is_some(),
837 )
838 };
839
840 let list = make_use_tree_list(make, vec![suffix], None)?;
841 Some(make.use_tree(prefix.clone(), Some(list), None, false))
842}
843
844mod version_sort {
847 #![allow(clippy::all)]
850
851 use std::cmp::Ordering;
852
853 use itertools::{EitherOrBoth, Itertools};
854
855 struct VersionChunkIter<'a> {
856 ident: &'a str,
857 start: usize,
858 }
859
860 impl<'a> VersionChunkIter<'a> {
861 pub(crate) fn new(ident: &'a str) -> Self {
862 Self { ident, start: 0 }
863 }
864
865 fn parse_numeric_chunk(
866 &mut self,
867 mut chars: std::str::CharIndices<'a>,
868 ) -> Option<VersionChunk<'a>> {
869 let mut end = self.start;
870 let mut is_end_of_chunk = false;
871
872 while let Some((idx, c)) = chars.next() {
873 end = self.start + idx;
874
875 if c.is_ascii_digit() {
876 continue;
877 }
878
879 is_end_of_chunk = true;
880 break;
881 }
882
883 let source = if is_end_of_chunk {
884 let value = &self.ident[self.start..end];
885 self.start = end;
886 value
887 } else {
888 let value = &self.ident[self.start..];
889 self.start = self.ident.len();
890 value
891 };
892
893 let zeros = source.chars().take_while(|c| *c == '0').count();
894 let value = source.parse::<usize>().ok()?;
895
896 Some(VersionChunk::Number { value, zeros, source })
897 }
898
899 fn parse_str_chunk(
900 &mut self,
901 mut chars: std::str::CharIndices<'a>,
902 ) -> Option<VersionChunk<'a>> {
903 let mut end = self.start;
904 let mut is_end_of_chunk = false;
905
906 while let Some((idx, c)) = chars.next() {
907 end = self.start + idx;
908
909 if c == '_' {
910 is_end_of_chunk = true;
911 break;
912 }
913
914 if !c.is_ascii_digit() {
915 continue;
916 }
917
918 is_end_of_chunk = true;
919 break;
920 }
921
922 let source = if is_end_of_chunk {
923 let value = &self.ident[self.start..end];
924 self.start = end;
925 value
926 } else {
927 let value = &self.ident[self.start..];
928 self.start = self.ident.len();
929 value
930 };
931
932 Some(VersionChunk::Str(source))
933 }
934 }
935
936 impl<'a> Iterator for VersionChunkIter<'a> {
937 type Item = VersionChunk<'a>;
938
939 fn next(&mut self) -> Option<Self::Item> {
940 let mut chars = self.ident[self.start..].char_indices();
941 let (_, next) = chars.next()?;
942
943 if next == '_' {
944 self.start = self.start + next.len_utf8();
945 return Some(VersionChunk::Underscore);
946 }
947
948 if next.is_ascii_digit() {
949 return self.parse_numeric_chunk(chars);
950 }
951
952 self.parse_str_chunk(chars)
953 }
954 }
955
956 #[derive(Debug, PartialEq, Eq)]
958 enum VersionChunk<'a> {
959 Underscore,
961 Str(&'a str),
963 Number { value: usize, zeros: usize, source: &'a str },
965 }
966
967 #[derive(Debug, PartialEq, Eq)]
969 enum MoreLeadingZeros {
970 Left,
971 Right,
972 Equal,
973 }
974
975 pub(super) fn version_sort(a: &str, b: &str) -> Ordering {
976 let iter_a = VersionChunkIter::new(a);
977 let iter_b = VersionChunkIter::new(b);
978 let mut more_leading_zeros = MoreLeadingZeros::Equal;
979
980 for either_or_both in iter_a.zip_longest(iter_b) {
981 match either_or_both {
982 EitherOrBoth::Left(_) => return std::cmp::Ordering::Greater,
983 EitherOrBoth::Right(_) => return std::cmp::Ordering::Less,
984 EitherOrBoth::Both(a, b) => match (a, b) {
985 (VersionChunk::Underscore, VersionChunk::Underscore) => {
986 continue;
987 }
988 (VersionChunk::Underscore, _) => return std::cmp::Ordering::Less,
989 (_, VersionChunk::Underscore) => return std::cmp::Ordering::Greater,
990 (VersionChunk::Str(ca), VersionChunk::Str(cb))
991 | (VersionChunk::Str(ca), VersionChunk::Number { source: cb, .. })
992 | (VersionChunk::Number { source: ca, .. }, VersionChunk::Str(cb)) => {
993 match ca.cmp(&cb) {
994 std::cmp::Ordering::Equal => {
995 continue;
996 }
997 order @ _ => return order,
998 }
999 }
1000 (
1001 VersionChunk::Number { value: va, zeros: lza, .. },
1002 VersionChunk::Number { value: vb, zeros: lzb, .. },
1003 ) => match va.cmp(&vb) {
1004 std::cmp::Ordering::Equal => {
1005 if lza == lzb {
1006 continue;
1007 }
1008
1009 if more_leading_zeros == MoreLeadingZeros::Equal && lza > lzb {
1010 more_leading_zeros = MoreLeadingZeros::Left;
1011 } else if more_leading_zeros == MoreLeadingZeros::Equal && lza < lzb {
1012 more_leading_zeros = MoreLeadingZeros::Right;
1013 }
1014 continue;
1015 }
1016 order @ _ => return order,
1017 },
1018 },
1019 }
1020 }
1021
1022 match more_leading_zeros {
1023 MoreLeadingZeros::Equal => std::cmp::Ordering::Equal,
1024 MoreLeadingZeros::Left => std::cmp::Ordering::Less,
1025 MoreLeadingZeros::Right => std::cmp::Ordering::Greater,
1026 }
1027 }
1028}