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 methods.into_iter().zip(sorted).for_each(|(old, new)| {
83 ted::replace(builder.make_ast_mut(old).syntax(), new.clone_for_update().syntax())
89 fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
90 let td = trait_definition(path, &ctx.sema)?;
95 .flat_map(|i| match i {
96 hir::AssocItem::Function(f) => Some(f),
100 .map(|(idx, func)| (func.name(ctx.db()).to_string(), idx))
105 fn trait_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<hir::Trait> {
106 match sema.resolve_path(path)? {
107 PathResolution::Def(hir::ModuleDef::Trait(trait_)) => Some(trait_),
112 fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
115 .flat_map(|i| match i {
116 ast::AssocItem::Fn(f) => Some(f),
119 .filter(|f| f.name().is_some())
125 use crate::tests::{check_assist, check_assist_not_applicable};
130 fn not_applicable_if_sorted() {
131 cov_mark::check!(not_applicable_if_sorted);
132 check_assist_not_applicable(
151 fn not_applicable_if_empty() {
152 check_assist_not_applicable(
157 $0impl Bar for Foo {}
163 fn reorder_impl_trait_methods() {