1 use itertools::Itertools;
2 use rustc_hash::FxHashMap;
4 use hir::{PathResolution, Semantics};
5 use ide_db::RootDatabase;
7 ast::{self, NameOwner},
11 use crate::{AssistContext, AssistId, AssistKind, Assists};
13 // Assist: reorder_impl
15 // Reorder the methods of an `impl Trait`. The methods will be ordered
16 // in the same order as in the trait definition.
26 // $0impl Foo for Bar {
48 pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
49 let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?;
50 let items = impl_ast.assoc_item_list()?;
51 let methods = get_methods(&items);
55 .and_then(|t| match t {
56 ast::Type::PathType(path) => Some(path),
61 let ranks = compute_method_ranks(&path, ctx)?;
62 let sorted: Vec<_> = methods
66 f.name().and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
70 // Don't edit already sorted methods:
71 if methods == sorted {
72 cov_mark::hit!(not_applicable_if_sorted);
76 let target = items.syntax().text_range();
78 AssistId("reorder_impl", AssistKind::RefactorRewrite),
82 let methods = methods.into_iter().map(|fn_| builder.make_mut(fn_)).collect::<Vec<_>>();
86 .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax()));
91 fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
92 let td = trait_definition(path, &ctx.sema)?;
97 .flat_map(|i| match i {
98 hir::AssocItem::Function(f) => Some(f),
102 .map(|(idx, func)| (func.name(ctx.db()).to_string(), idx))
107 fn trait_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<hir::Trait> {
108 match sema.resolve_path(path)? {
109 PathResolution::Def(hir::ModuleDef::Trait(trait_)) => Some(trait_),
114 fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
117 .flat_map(|i| match i {
118 ast::AssocItem::Fn(f) => Some(f),
121 .filter(|f| f.name().is_some())
127 use crate::tests::{check_assist, check_assist_not_applicable};
132 fn not_applicable_if_sorted() {
133 cov_mark::check!(not_applicable_if_sorted);
134 check_assist_not_applicable(
153 fn not_applicable_if_empty() {
154 check_assist_not_applicable(
159 $0impl Bar for Foo {}
165 fn reorder_impl_trait_functions() {
204 fn reorder_impl_trait_methods_uneven_ident_lengths() {
210 fn fooo(&mut self) {}
215 fn fooo(&mut self) {}
216 fn foo(&mut self) {$0}
221 fn fooo(&mut self) {}
227 fn fooo(&mut self) {}