1 use itertools::Itertools;
2 use rustc_hash::FxHashMap;
4 use hir::{PathResolution, Semantics};
5 use ide_db::RootDatabase;
8 ast::{self, NameOwner},
13 use crate::{AssistContext, AssistId, AssistKind, Assists};
15 // Assist: reorder_impl
17 // Reorder the methods of an `impl Trait`. The methods will be ordered
18 // in the same order as in the trait definition.
28 // $0impl Foo for Bar {
50 pub(crate) fn reorder_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
51 let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?;
52 let items = impl_ast.assoc_item_list()?;
53 let methods = get_methods(&items);
57 .and_then(|t| match t {
58 ast::Type::PathType(path) => Some(path),
63 let ranks = compute_method_ranks(&path, ctx)?;
64 let sorted: Vec<_> = methods
68 f.name().and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
72 // Don't edit already sorted methods:
73 if methods == sorted {
74 mark::hit!(not_applicable_if_sorted);
78 let target = items.syntax().text_range();
79 acc.add(AssistId("reorder_impl", AssistKind::RefactorRewrite), "Sort methods", target, |edit| {
80 let mut rewriter = algo::SyntaxRewriter::default();
81 for (old, new) in methods.iter().zip(&sorted) {
82 rewriter.replace(old.syntax(), new.syntax());
84 edit.rewrite(rewriter);
88 fn compute_method_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
89 let td = trait_definition(path, &ctx.sema)?;
94 .flat_map(|i| match i {
95 hir::AssocItem::Function(f) => Some(f),
99 .map(|(idx, func)| ((func.name(ctx.db()).to_string(), idx)))
104 fn trait_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<hir::Trait> {
105 match sema.resolve_path(path)? {
106 PathResolution::Def(hir::ModuleDef::Trait(trait_)) => Some(trait_),
111 fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
114 .flat_map(|i| match i {
115 ast::AssocItem::Fn(f) => Some(f),
118 .filter(|f| f.name().is_some())
124 use test_utils::mark;
126 use crate::tests::{check_assist, check_assist_not_applicable};
131 fn not_applicable_if_sorted() {
132 mark::check!(not_applicable_if_sorted);
133 check_assist_not_applicable(
152 fn not_applicable_if_empty() {
153 check_assist_not_applicable(
158 $0impl Bar for Foo {}
164 fn reorder_impl_trait_methods() {