Skip to content

Commit

Permalink
Attempt rust-lang#1 Alphabetically Sorting Methods
Browse files Browse the repository at this point in the history
  • Loading branch information
fisherdarling committed Dec 10, 2020
1 parent 41321d9 commit 7787554
Show file tree
Hide file tree
Showing 2 changed files with 244 additions and 0 deletions.
242 changes: 242 additions & 0 deletions crates/assists/src/handlers/reorder_methods_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
use ast::{AssocItemList, Fn};
use itertools::Itertools;
use rustc_hash::FxHashMap;

use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use ide_db::RootDatabase;
use syntax::{
algo,
ast::{self, AssocItem, NameOwner},
match_ast, AstNode, SyntaxKind,
SyntaxKind::*,
SyntaxNode,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: reorder_methods_sort
//
// Reorder the fields of record literals and record patterns in the same order as in
// the definition.
//
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = <|>Foo {bar: 0, foo: 1}
// ```
// ->
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = Foo {foo: 1, bar: 0}
// ```
//
pub(crate) fn reorder_methods_sort(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
reorder(acc, ctx) //.or_else(|| reorder::<ast::RecordPat>(acc, ctx))
}

fn reorder(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let impl_ast = ctx.find_node_at_offset::<ast::Impl>()?;

let items = impl_ast.assoc_item_list()?;

let methods = get_methods(&items);
let sorted: Vec<_> =
methods.iter().cloned().sorted_by_key(|f| f.name().unwrap().text().to_string()).collect();

let target = items.syntax().text_range();
acc.add(
AssistId("reorder_methods_sort", AssistKind::RefactorRewrite),
"Sort impl methods",
target,
|edit| {
let mut rewriter = algo::SyntaxRewriter::default();
for (old, new) in methods.iter().zip(&sorted) {
rewriter.replace(old.syntax(), new.syntax());
}
edit.rewrite(rewriter);
},
)

// println!("Fns: {:?}", fns);
// items.syntax().text_range();

// let path = record.syntax().children().find_map(ast::Path::cast)?;

// println!("Path: {}", path);

// let ranks = compute_fields_ranks(&path, &ctx)?;

// let fields = get_fields(&record.syntax());
// let sorted_fields = sorted_by_rank(&fields, |node| {
// *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
// });

// if sorted_fields == fields {
// return None;
// }

// let target = record.syntax().text_range();
// acc.add(
// AssistId("reorder_methods_sort", AssistKind::RefactorRewrite),
// "Reorder record fields",
// target,
// |edit| {
// let mut rewriter = algo::SyntaxRewriter::default();
// for (old, new) in fields.iter().zip(&sorted_fields) {
// rewriter.replace(old, new);
// }
// edit.rewrite(rewriter);
// },
// )
}

fn get_methods(items: &AssocItemList) -> Vec<Fn> {
items
.assoc_items()
.flat_map(|i| match i {
AssocItem::Fn(f) => Some(f),
_ => None,
})
.filter(|f| f.name().is_some())
.collect()
}

struct Foo {
c: usize,
}
impl Foo {
fn ten() -> usize {
10
}
fn add(&mut self, b: usize) {
self.c += b
}
fn sub(&mut self, b: usize) {
self.c -= b
}
}

#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};

use super::*;

#[test]
fn not_applicable_if_sorted() {
check_assist_not_applicable(
reorder_methods_sort,
r#"
struct Foo {
foo: i32,
bar: i32,
}
const test: Foo = <|>Foo { foo: 0, bar: 0 };
"#,
)
}

#[test]
fn trivial_empty_impl() {
check_assist_not_applicable(
reorder_methods_sort,
r#"
struct Foo {};
<|>impl Foo {}
"#,
)
}

#[test]
fn reorder_impl_methods() {
check_assist(
reorder_methods_sort,
r#"
struct Foo {c: usize}
<|>impl Foo {
fn sub(&mut self, b: usize) { self.c -= b }
fn ten() -> usize { 10 }
fn add(&mut self, b: usize) { self.c += b }
}
"#,
r#"
struct Foo {c: usize}
impl Foo {
fn add(&mut self, b: usize) { self.c += b }
fn sub(&mut self, b: usize) { self.c -= b }
fn ten() -> usize { 10 }
}
"#,
)
}

#[test]
fn reorder_struct_pattern() {
check_assist(
reorder_methods_sort,
r#"
struct Foo { foo: i64, bar: i64, baz: i64 }
fn f(f: Foo) -> {
match f {
<|>Foo { baz: 0, ref mut bar, .. } => (),
_ => ()
}
}
"#,
r#"
struct Foo { foo: i64, bar: i64, baz: i64 }
fn f(f: Foo) -> {
match f {
Foo { ref mut bar, baz: 0, .. } => (),
_ => ()
}
}
"#,
)
}

#[test]
fn reorder_with_extra_field() {
check_assist(
reorder_methods_sort,
r#"
struct Foo {
foo: String,
bar: String,
}
impl Foo {
fn new() -> Foo {
let foo = String::new();
<|>Foo {
bar: foo.clone(),
extra: "Extra field",
foo,
}
}
}
"#,
r#"
struct Foo {
foo: String,
bar: String,
}
impl Foo {
fn new() -> Foo {
let foo = String::new();
Foo {
foo,
bar: foo.clone(),
extra: "Extra field",
}
}
}
"#,
)
}
}
2 changes: 2 additions & 0 deletions crates/assists/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ mod handlers {
mod remove_mut;
mod remove_unused_param;
mod reorder_fields;
mod reorder_methods_sort;
mod replace_derive_with_manual_impl;
mod replace_if_let_with_match;
mod replace_impl_trait_with_generic;
Expand Down Expand Up @@ -207,6 +208,7 @@ mod handlers {
remove_mut::remove_mut,
remove_unused_param::remove_unused_param,
reorder_fields::reorder_fields,
reorder_methods_sort::reorder_methods_sort,
replace_derive_with_manual_impl::replace_derive_with_manual_impl,
replace_if_let_with_match::replace_if_let_with_match,
replace_if_let_with_match::replace_match_with_if_let,
Expand Down

0 comments on commit 7787554

Please sign in to comment.