1 use itertools::Itertools;
2 use rustc_hash::FxHashMap;
4 use hir::{PathResolution, Semantics};
5 use ide_db::RootDatabase;
8 ast::{self, NameOwner},
12 use crate::{AssistContext, AssistId, AssistKind, Assists};
14 // Assist: reorder_impl
16 // Reorder the methods of an `impl Trait`. The methods will be ordered
17 // in the same order as in the trait definition.
27 // $0impl Foo for Bar {
49 pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
50 let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?;
51 let items = impl_ast.assoc_item_list()?;
52 let methods = get_methods(&items);
56 .and_then(|t| match t {
57 ast::Type::PathType(path) => Some(path),
62 let ranks = compute_method_ranks(&path, ctx)?;
63 let sorted: Vec<_> = methods
67 f.name().and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
71 // Don't edit already sorted methods:
72 if methods == sorted {
73 cov_mark::hit!(not_applicable_if_sorted);
77 let target = items.syntax().text_range();
78 acc.add(AssistId("reorder_impl", AssistKind::RefactorRewrite), "Sort methods", target, |edit| {
79 let mut rewriter = algo::SyntaxRewriter::default();
80 for (old, new) in methods.iter().zip(&sorted) {
81 rewriter.replace(old.syntax(), new.syntax());
83 edit.rewrite(rewriter);
87 fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
88 let td = trait_definition(path, &ctx.sema)?;
93 .flat_map(|i| match i {
94 hir::AssocItem::Function(f) => Some(f),
98 .map(|(idx, func)| ((func.name(ctx.db()).to_string(), idx)))
103 fn trait_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<hir::Trait> {
104 match sema.resolve_path(path)? {
105 PathResolution::Def(hir::ModuleDef::Trait(trait_)) => Some(trait_),
110 fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
113 .flat_map(|i| match i {
114 ast::AssocItem::Fn(f) => Some(f),
117 .filter(|f| f.name().is_some())
123 use crate::tests::{check_assist, check_assist_not_applicable};
128 fn not_applicable_if_sorted() {
129 cov_mark::check!(not_applicable_if_sorted);
130 check_assist_not_applicable(
149 fn not_applicable_if_empty() {
150 check_assist_not_applicable(
155 $0impl Bar for Foo {}
161 fn reorder_impl_trait_methods() {