diff options
Diffstat (limited to 'crates/ide_assists/src')
3 files changed, 60 insertions, 104 deletions
diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs index 63cea754d..0148635f9 100644 --- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -3,9 +3,9 @@ use syntax::ast::{self, AstNode}; | |||
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | assist_context::{AssistContext, Assists}, | 5 | assist_context::{AssistContext, Assists}, |
6 | utils::add_trait_assoc_items_to_impl, | 6 | utils::{ |
7 | utils::DefaultMethods, | 7 | add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, |
8 | utils::{filter_assoc_items, render_snippet, Cursor}, | 8 | }, |
9 | AssistId, AssistKind, | 9 | AssistId, AssistKind, |
10 | }; | 10 | }; |
11 | 11 | ||
diff --git a/crates/ide_assists/src/handlers/convert_comment_block.rs b/crates/ide_assists/src/handlers/convert_comment_block.rs index 9dc3ee28f..d202a85f9 100644 --- a/crates/ide_assists/src/handlers/convert_comment_block.rs +++ b/crates/ide_assists/src/handlers/convert_comment_block.rs | |||
@@ -1,13 +1,6 @@ | |||
1 | use itertools::Itertools; | 1 | use itertools::Itertools; |
2 | use syntax::{ | 2 | use syntax::{ |
3 | ast::{ | 3 | ast::{self, edit::IndentLevel, Comment, CommentKind, CommentShape, Whitespace}, |
4 | self, | ||
5 | edit::IndentLevel, | ||
6 | Comment, CommentKind, | ||
7 | CommentPlacement::{Inner, Outer}, | ||
8 | CommentShape::{self, Block, Line}, | ||
9 | Whitespace, | ||
10 | }, | ||
11 | AstToken, Direction, SyntaxElement, TextRange, | 4 | AstToken, Direction, SyntaxElement, TextRange, |
12 | }; | 5 | }; |
13 | 6 | ||
@@ -29,21 +22,18 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
29 | /// */ | 22 | /// */ |
30 | /// ``` | 23 | /// ``` |
31 | pub(crate) fn convert_comment_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 24 | pub(crate) fn convert_comment_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
32 | if let Some(comment) = ctx.find_token_at_offset::<ast::Comment>() { | 25 | let comment = ctx.find_token_at_offset::<ast::Comment>()?; |
33 | // Only allow comments which are alone on their line | 26 | // Only allow comments which are alone on their line |
34 | if let Some(prev) = comment.syntax().prev_token() { | 27 | if let Some(prev) = comment.syntax().prev_token() { |
35 | if Whitespace::cast(prev).filter(|w| w.text().contains('\n')).is_none() { | 28 | if Whitespace::cast(prev).filter(|w| w.text().contains('\n')).is_none() { |
36 | return None; | 29 | return None; |
37 | } | ||
38 | } | 30 | } |
39 | |||
40 | return match comment.kind().shape { | ||
41 | ast::CommentShape::Block => block_to_line(acc, comment), | ||
42 | ast::CommentShape::Line => line_to_block(acc, comment), | ||
43 | }; | ||
44 | } | 31 | } |
45 | 32 | ||
46 | return None; | 33 | match comment.kind().shape { |
34 | ast::CommentShape::Block => block_to_line(acc, comment), | ||
35 | ast::CommentShape::Line => line_to_block(acc, comment), | ||
36 | } | ||
47 | } | 37 | } |
48 | 38 | ||
49 | fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> { | 39 | fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> { |
@@ -55,8 +45,7 @@ fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> { | |||
55 | target, | 45 | target, |
56 | |edit| { | 46 | |edit| { |
57 | let indentation = IndentLevel::from_token(comment.syntax()); | 47 | let indentation = IndentLevel::from_token(comment.syntax()); |
58 | let line_prefix = | 48 | let line_prefix = CommentKind { shape: CommentShape::Line, ..comment.kind() }.prefix(); |
59 | comment_kind_prefix(CommentKind { shape: CommentShape::Line, ..comment.kind() }); | ||
60 | 49 | ||
61 | let text = comment.text(); | 50 | let text = comment.text(); |
62 | let text = &text[comment.prefix().len()..(text.len() - "*/".len())].trim(); | 51 | let text = &text[comment.prefix().len()..(text.len() - "*/".len())].trim(); |
@@ -105,7 +94,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> { | |||
105 | comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n"); | 94 | comments.into_iter().map(|c| line_comment_text(indentation, c)).join("\n"); |
106 | 95 | ||
107 | let block_prefix = | 96 | let block_prefix = |
108 | comment_kind_prefix(CommentKind { shape: CommentShape::Block, ..comment.kind() }); | 97 | CommentKind { shape: CommentShape::Block, ..comment.kind() }.prefix(); |
109 | 98 | ||
110 | let output = | 99 | let output = |
111 | format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation.to_string()); | 100 | format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation.to_string()); |
@@ -182,17 +171,6 @@ fn line_comment_text(indentation: IndentLevel, comm: ast::Comment) -> String { | |||
182 | } | 171 | } |
183 | } | 172 | } |
184 | 173 | ||
185 | fn comment_kind_prefix(ck: ast::CommentKind) -> &'static str { | ||
186 | match (ck.shape, ck.doc) { | ||
187 | (Line, Some(Inner)) => "//!", | ||
188 | (Line, Some(Outer)) => "///", | ||
189 | (Line, None) => "//", | ||
190 | (Block, Some(Inner)) => "/*!", | ||
191 | (Block, Some(Outer)) => "/**", | ||
192 | (Block, None) => "/*", | ||
193 | } | ||
194 | } | ||
195 | |||
196 | #[cfg(test)] | 174 | #[cfg(test)] |
197 | mod tests { | 175 | mod tests { |
198 | use crate::tests::{check_assist, check_assist_not_applicable}; | 176 | use crate::tests::{check_assist, check_assist_not_applicable}; |
diff --git a/crates/ide_assists/src/handlers/reorder_fields.rs b/crates/ide_assists/src/handlers/reorder_fields.rs index 794c89323..383ca6c47 100644 --- a/crates/ide_assists/src/handlers/reorder_fields.rs +++ b/crates/ide_assists/src/handlers/reorder_fields.rs | |||
@@ -1,9 +1,6 @@ | |||
1 | use itertools::Itertools; | ||
2 | use rustc_hash::FxHashMap; | 1 | use rustc_hash::FxHashMap; |
3 | 2 | ||
4 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | 3 | use syntax::{algo, ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode}; |
5 | use ide_db::RootDatabase; | ||
6 | use syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode}; | ||
7 | 4 | ||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
9 | 6 | ||
@@ -23,26 +20,39 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
23 | // ``` | 20 | // ``` |
24 | // | 21 | // |
25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 22 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | reorder::<ast::RecordExpr>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) | 23 | let record = ctx |
27 | } | 24 | .find_node_at_offset::<ast::RecordExpr>() |
25 | .map(|it| it.syntax().clone()) | ||
26 | .or_else(|| ctx.find_node_at_offset::<ast::RecordPat>().map(|it| it.syntax().clone()))?; | ||
28 | 27 | ||
29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 28 | let path = record.children().find_map(ast::Path::cast)?; |
30 | let record = ctx.find_node_at_offset::<R>()?; | ||
31 | let path = record.syntax().children().find_map(ast::Path::cast)?; | ||
32 | 29 | ||
33 | let ranks = compute_fields_ranks(&path, &ctx)?; | 30 | let ranks = compute_fields_ranks(&path, &ctx)?; |
34 | 31 | ||
35 | let fields = get_fields(&record.syntax()); | 32 | let fields: Vec<SyntaxNode> = { |
36 | let sorted_fields = sorted_by_rank(&fields, |node| { | 33 | let field_kind = match record.kind() { |
37 | *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value()) | 34 | RECORD_EXPR => RECORD_EXPR_FIELD, |
38 | }); | 35 | RECORD_PAT => RECORD_PAT_FIELD, |
36 | _ => { | ||
37 | stdx::never!(); | ||
38 | return None; | ||
39 | } | ||
40 | }; | ||
41 | record.children().flat_map(|n| n.children()).filter(|n| n.kind() == field_kind).collect() | ||
42 | }; | ||
43 | |||
44 | let sorted_fields = { | ||
45 | let mut fields = fields.clone(); | ||
46 | fields.sort_by_key(|node| *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())); | ||
47 | fields | ||
48 | }; | ||
39 | 49 | ||
40 | if sorted_fields == fields { | 50 | if sorted_fields == fields { |
41 | cov_mark::hit!(reorder_sorted_fields); | 51 | cov_mark::hit!(reorder_sorted_fields); |
42 | return None; | 52 | return None; |
43 | } | 53 | } |
44 | 54 | ||
45 | let target = record.syntax().text_range(); | 55 | let target = record.text_range(); |
46 | acc.add( | 56 | acc.add( |
47 | AssistId("reorder_fields", AssistKind::RefactorRewrite), | 57 | AssistId("reorder_fields", AssistKind::RefactorRewrite), |
48 | "Reorder record fields", | 58 | "Reorder record fields", |
@@ -57,14 +67,6 @@ fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
57 | ) | 67 | ) |
58 | } | 68 | } |
59 | 69 | ||
60 | fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> { | ||
61 | match node.kind() { | ||
62 | RECORD_EXPR => vec![RECORD_EXPR_FIELD], | ||
63 | RECORD_PAT => vec![RECORD_PAT_FIELD, IDENT_PAT], | ||
64 | _ => vec![], | ||
65 | } | ||
66 | } | ||
67 | |||
68 | fn get_field_name(node: &SyntaxNode) -> String { | 70 | fn get_field_name(node: &SyntaxNode) -> String { |
69 | let res = match_ast! { | 71 | let res = match_ast! { |
70 | match node { | 72 | match node { |
@@ -76,34 +78,20 @@ fn get_field_name(node: &SyntaxNode) -> String { | |||
76 | res.unwrap_or_default() | 78 | res.unwrap_or_default() |
77 | } | 79 | } |
78 | 80 | ||
79 | fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> { | 81 | fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { |
80 | let kinds = get_fields_kind(record); | 82 | let strukt = match ctx.sema.resolve_path(path) { |
81 | record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect() | 83 | Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(it)))) => it, |
82 | } | 84 | _ => return None, |
83 | 85 | }; | |
84 | fn sorted_by_rank( | ||
85 | fields: &[SyntaxNode], | ||
86 | get_rank: impl Fn(&SyntaxNode) -> usize, | ||
87 | ) -> Vec<SyntaxNode> { | ||
88 | fields.iter().cloned().sorted_by_key(get_rank).collect() | ||
89 | } | ||
90 | 86 | ||
91 | fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> { | 87 | let res = strukt |
92 | match sema.resolve_path(path) { | 88 | .fields(ctx.db()) |
93 | Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s), | 89 | .iter() |
94 | _ => None, | 90 | .enumerate() |
95 | } | 91 | .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx)) |
96 | } | 92 | .collect(); |
97 | 93 | ||
98 | fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { | 94 | Some(res) |
99 | Some( | ||
100 | struct_definition(path, &ctx.sema)? | ||
101 | .fields(ctx.db()) | ||
102 | .iter() | ||
103 | .enumerate() | ||
104 | .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx)) | ||
105 | .collect(), | ||
106 | ) | ||
107 | } | 95 | } |
108 | 96 | ||
109 | #[cfg(test)] | 97 | #[cfg(test)] |
@@ -118,11 +106,7 @@ mod tests { | |||
118 | check_assist_not_applicable( | 106 | check_assist_not_applicable( |
119 | reorder_fields, | 107 | reorder_fields, |
120 | r#" | 108 | r#" |
121 | struct Foo { | 109 | struct Foo { foo: i32, bar: i32 } |
122 | foo: i32, | ||
123 | bar: i32, | ||
124 | } | ||
125 | |||
126 | const test: Foo = $0Foo { foo: 0, bar: 0 }; | 110 | const test: Foo = $0Foo { foo: 0, bar: 0 }; |
127 | "#, | 111 | "#, |
128 | ) | 112 | ) |
@@ -133,8 +117,8 @@ const test: Foo = $0Foo { foo: 0, bar: 0 }; | |||
133 | check_assist_not_applicable( | 117 | check_assist_not_applicable( |
134 | reorder_fields, | 118 | reorder_fields, |
135 | r#" | 119 | r#" |
136 | struct Foo {}; | 120 | struct Foo {} |
137 | const test: Foo = $0Foo {} | 121 | const test: Foo = $0Foo {}; |
138 | "#, | 122 | "#, |
139 | ) | 123 | ) |
140 | } | 124 | } |
@@ -144,12 +128,12 @@ const test: Foo = $0Foo {} | |||
144 | check_assist( | 128 | check_assist( |
145 | reorder_fields, | 129 | reorder_fields, |
146 | r#" | 130 | r#" |
147 | struct Foo {foo: i32, bar: i32}; | 131 | struct Foo { foo: i32, bar: i32 } |
148 | const test: Foo = $0Foo {bar: 0, foo: 1} | 132 | const test: Foo = $0Foo { bar: 0, foo: 1 }; |
149 | "#, | 133 | "#, |
150 | r#" | 134 | r#" |
151 | struct Foo {foo: i32, bar: i32}; | 135 | struct Foo { foo: i32, bar: i32 } |
152 | const test: Foo = Foo {foo: 1, bar: 0} | 136 | const test: Foo = Foo { foo: 1, bar: 0 }; |
153 | "#, | 137 | "#, |
154 | ) | 138 | ) |
155 | } | 139 | } |
@@ -186,10 +170,7 @@ fn f(f: Foo) -> { | |||
186 | check_assist( | 170 | check_assist( |
187 | reorder_fields, | 171 | reorder_fields, |
188 | r#" | 172 | r#" |
189 | struct Foo { | 173 | struct Foo { foo: String, bar: String } |
190 | foo: String, | ||
191 | bar: String, | ||
192 | } | ||
193 | 174 | ||
194 | impl Foo { | 175 | impl Foo { |
195 | fn new() -> Foo { | 176 | fn new() -> Foo { |
@@ -203,10 +184,7 @@ impl Foo { | |||
203 | } | 184 | } |
204 | "#, | 185 | "#, |
205 | r#" | 186 | r#" |
206 | struct Foo { | 187 | struct Foo { foo: String, bar: String } |
207 | foo: String, | ||
208 | bar: String, | ||
209 | } | ||
210 | 188 | ||
211 | impl Foo { | 189 | impl Foo { |
212 | fn new() -> Foo { | 190 | fn new() -> Foo { |