diff options
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r-- | crates/assists/src/handlers/auto_import.rs | 9 | ||||
-rw-r--r-- | crates/assists/src/handlers/inline_local_variable.rs | 45 | ||||
-rw-r--r-- | crates/assists/src/handlers/qualify_path.rs | 40 | ||||
-rw-r--r-- | crates/assists/src/handlers/unmerge_use.rs | 231 |
4 files changed, 281 insertions, 44 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 55620f0f3..4e2a4fcd9 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -1,13 +1,11 @@ | |||
1 | use ide_db::helpers::{ | 1 | use ide_db::helpers::{ |
2 | import_assets::{ImportAssets, ImportCandidate}, | ||
2 | insert_use::{insert_use, ImportScope}, | 3 | insert_use::{insert_use, ImportScope}, |
3 | mod_path_to_ast, | 4 | mod_path_to_ast, |
4 | }; | 5 | }; |
5 | use syntax::ast; | 6 | use syntax::ast; |
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
8 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
9 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
10 | }; | ||
11 | 9 | ||
12 | // Feature: Auto Import | 10 | // Feature: Auto Import |
13 | // | 11 | // |
@@ -121,8 +119,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
121 | 119 | ||
122 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { | 120 | fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { |
123 | let name = match import_candidate { | 121 | let name = match import_candidate { |
124 | ImportCandidate::UnqualifiedName(candidate) | 122 | ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name), |
125 | | ImportCandidate::QualifierStart(candidate) => format!("Import {}", &candidate.name), | ||
126 | ImportCandidate::TraitAssocItem(candidate) => { | 123 | ImportCandidate::TraitAssocItem(candidate) => { |
127 | format!("Import a trait for item {}", &candidate.name) | 124 | format!("Import a trait for item {}", &candidate.name) |
128 | } | 125 | } |
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs index dc798daaa..0e63a60e8 100644 --- a/crates/assists/src/handlers/inline_local_variable.rs +++ b/crates/assists/src/handlers/inline_local_variable.rs | |||
@@ -79,29 +79,30 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O | |||
79 | None => return Ok(false), | 79 | None => return Ok(false), |
80 | }; | 80 | }; |
81 | 81 | ||
82 | Ok(!matches!((&initializer_expr, usage_parent), | 82 | Ok(!matches!( |
83 | (&initializer_expr, usage_parent), | ||
83 | (ast::Expr::CallExpr(_), _) | 84 | (ast::Expr::CallExpr(_), _) |
84 | | (ast::Expr::IndexExpr(_), _) | 85 | | (ast::Expr::IndexExpr(_), _) |
85 | | (ast::Expr::MethodCallExpr(_), _) | 86 | | (ast::Expr::MethodCallExpr(_), _) |
86 | | (ast::Expr::FieldExpr(_), _) | 87 | | (ast::Expr::FieldExpr(_), _) |
87 | | (ast::Expr::TryExpr(_), _) | 88 | | (ast::Expr::TryExpr(_), _) |
88 | | (ast::Expr::RefExpr(_), _) | 89 | | (ast::Expr::RefExpr(_), _) |
89 | | (ast::Expr::Literal(_), _) | 90 | | (ast::Expr::Literal(_), _) |
90 | | (ast::Expr::TupleExpr(_), _) | 91 | | (ast::Expr::TupleExpr(_), _) |
91 | | (ast::Expr::ArrayExpr(_), _) | 92 | | (ast::Expr::ArrayExpr(_), _) |
92 | | (ast::Expr::ParenExpr(_), _) | 93 | | (ast::Expr::ParenExpr(_), _) |
93 | | (ast::Expr::PathExpr(_), _) | 94 | | (ast::Expr::PathExpr(_), _) |
94 | | (ast::Expr::BlockExpr(_), _) | 95 | | (ast::Expr::BlockExpr(_), _) |
95 | | (ast::Expr::EffectExpr(_), _) | 96 | | (ast::Expr::EffectExpr(_), _) |
96 | | (_, ast::Expr::CallExpr(_)) | 97 | | (_, ast::Expr::CallExpr(_)) |
97 | | (_, ast::Expr::TupleExpr(_)) | 98 | | (_, ast::Expr::TupleExpr(_)) |
98 | | (_, ast::Expr::ArrayExpr(_)) | 99 | | (_, ast::Expr::ArrayExpr(_)) |
99 | | (_, ast::Expr::ParenExpr(_)) | 100 | | (_, ast::Expr::ParenExpr(_)) |
100 | | (_, ast::Expr::ForExpr(_)) | 101 | | (_, ast::Expr::ForExpr(_)) |
101 | | (_, ast::Expr::WhileExpr(_)) | 102 | | (_, ast::Expr::WhileExpr(_)) |
102 | | (_, ast::Expr::BreakExpr(_)) | 103 | | (_, ast::Expr::BreakExpr(_)) |
103 | | (_, ast::Expr::ReturnExpr(_)) | 104 | | (_, ast::Expr::ReturnExpr(_)) |
104 | | (_, ast::Expr::MatchExpr(_)) | 105 | | (_, ast::Expr::MatchExpr(_)) |
105 | )) | 106 | )) |
106 | }) | 107 | }) |
107 | .collect::<Result<Vec<_>, _>>()?; | 108 | .collect::<Result<Vec<_>, _>>()?; |
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs index f7fbf37f4..a7d9fd4dc 100644 --- a/crates/assists/src/handlers/qualify_path.rs +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use hir::AsName; | 3 | use hir::AsName; |
4 | use ide_db::helpers::mod_path_to_ast; | 4 | use ide_db::helpers::{ |
5 | import_assets::{ImportAssets, ImportCandidate}, | ||
6 | mod_path_to_ast, | ||
7 | }; | ||
5 | use ide_db::RootDatabase; | 8 | use ide_db::RootDatabase; |
6 | use syntax::{ | 9 | use syntax::{ |
7 | ast, | 10 | ast, |
@@ -12,7 +15,6 @@ use test_utils::mark; | |||
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{ |
14 | assist_context::{AssistContext, Assists}, | 17 | assist_context::{AssistContext, Assists}, |
15 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
16 | AssistId, AssistKind, GroupLabel, | 18 | AssistId, AssistKind, GroupLabel, |
17 | }; | 19 | }; |
18 | 20 | ||
@@ -53,17 +55,18 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
53 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 55 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; |
54 | 56 | ||
55 | let qualify_candidate = match candidate { | 57 | let qualify_candidate = match candidate { |
56 | ImportCandidate::QualifierStart(_) => { | 58 | ImportCandidate::Path(candidate) => { |
57 | mark::hit!(qualify_path_qualifier_start); | 59 | if candidate.qualifier.is_some() { |
58 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 60 | mark::hit!(qualify_path_qualifier_start); |
59 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); | 61 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; |
60 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) | 62 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); |
61 | } | 63 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) |
62 | ImportCandidate::UnqualifiedName(_) => { | 64 | } else { |
63 | mark::hit!(qualify_path_unqualified_name); | 65 | mark::hit!(qualify_path_unqualified_name); |
64 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | 66 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; |
65 | let generics = path.segment()?.generic_arg_list(); | 67 | let generics = path.segment()?.generic_arg_list(); |
66 | QualifyCandidate::UnqualifiedName(generics) | 68 | QualifyCandidate::UnqualifiedName(generics) |
69 | } | ||
67 | } | 70 | } |
68 | ImportCandidate::TraitAssocItem(_) => { | 71 | ImportCandidate::TraitAssocItem(_) => { |
69 | mark::hit!(qualify_path_trait_assoc_item); | 72 | mark::hit!(qualify_path_trait_assoc_item); |
@@ -186,7 +189,7 @@ fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> { | |||
186 | 189 | ||
187 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { | 190 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { |
188 | let name = match candidate { | 191 | let name = match candidate { |
189 | ImportCandidate::UnqualifiedName(it) | ImportCandidate::QualifierStart(it) => &it.name, | 192 | ImportCandidate::Path(it) => &it.name, |
190 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, | 193 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, |
191 | }; | 194 | }; |
192 | GroupLabel(format!("Qualify {}", name)) | 195 | GroupLabel(format!("Qualify {}", name)) |
@@ -194,8 +197,13 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { | |||
194 | 197 | ||
195 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { | 198 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { |
196 | match candidate { | 199 | match candidate { |
197 | ImportCandidate::UnqualifiedName(_) => format!("Qualify as `{}`", &import), | 200 | ImportCandidate::Path(candidate) => { |
198 | ImportCandidate::QualifierStart(_) => format!("Qualify with `{}`", &import), | 201 | if candidate.qualifier.is_some() { |
202 | format!("Qualify with `{}`", &import) | ||
203 | } else { | ||
204 | format!("Qualify as `{}`", &import) | ||
205 | } | ||
206 | } | ||
199 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), | 207 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), |
200 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), | 208 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), |
201 | } | 209 | } |
diff --git a/crates/assists/src/handlers/unmerge_use.rs b/crates/assists/src/handlers/unmerge_use.rs new file mode 100644 index 000000000..3dbef8e51 --- /dev/null +++ b/crates/assists/src/handlers/unmerge_use.rs | |||
@@ -0,0 +1,231 @@ | |||
1 | use syntax::{ | ||
2 | algo::SyntaxRewriter, | ||
3 | ast::{self, edit::AstNodeEdit, VisibilityOwner}, | ||
4 | AstNode, SyntaxKind, | ||
5 | }; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use crate::{ | ||
9 | assist_context::{AssistContext, Assists}, | ||
10 | AssistId, AssistKind, | ||
11 | }; | ||
12 | |||
13 | // Assist: unmerge_use | ||
14 | // | ||
15 | // Extracts single use item from use list. | ||
16 | // | ||
17 | // ``` | ||
18 | // use std::fmt::{Debug, Display$0}; | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // use std::fmt::{Debug}; | ||
23 | // use std::fmt::Display; | ||
24 | // ``` | ||
25 | pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
26 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | ||
27 | |||
28 | let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; | ||
29 | if tree_list.use_trees().count() < 2 { | ||
30 | mark::hit!(skip_single_use_item); | ||
31 | return None; | ||
32 | } | ||
33 | |||
34 | let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; | ||
35 | let path = resolve_full_path(&tree)?; | ||
36 | |||
37 | let target = tree.syntax().text_range(); | ||
38 | acc.add( | ||
39 | AssistId("unmerge_use", AssistKind::RefactorRewrite), | ||
40 | "Unmerge use", | ||
41 | target, | ||
42 | |builder| { | ||
43 | let new_use = ast::make::use_( | ||
44 | use_.visibility(), | ||
45 | ast::make::use_tree( | ||
46 | path, | ||
47 | tree.use_tree_list(), | ||
48 | tree.rename(), | ||
49 | tree.star_token().is_some(), | ||
50 | ), | ||
51 | ); | ||
52 | |||
53 | let mut rewriter = SyntaxRewriter::default(); | ||
54 | rewriter += tree.remove(); | ||
55 | rewriter.insert_after(use_.syntax(), &ast::make::tokens::single_newline()); | ||
56 | if let ident_level @ 1..=usize::MAX = use_.indent_level().0 as usize { | ||
57 | rewriter.insert_after( | ||
58 | use_.syntax(), | ||
59 | &ast::make::tokens::whitespace(&" ".repeat(4 * ident_level)), | ||
60 | ); | ||
61 | } | ||
62 | rewriter.insert_after(use_.syntax(), new_use.syntax()); | ||
63 | |||
64 | builder.rewrite(rewriter); | ||
65 | }, | ||
66 | ) | ||
67 | } | ||
68 | |||
69 | fn resolve_full_path(tree: &ast::UseTree) -> Option<ast::Path> { | ||
70 | let mut paths = tree | ||
71 | .syntax() | ||
72 | .ancestors() | ||
73 | .take_while(|n| n.kind() != SyntaxKind::USE_KW) | ||
74 | .filter_map(ast::UseTree::cast) | ||
75 | .filter_map(|t| t.path()); | ||
76 | |||
77 | let mut final_path = paths.next()?; | ||
78 | for path in paths { | ||
79 | final_path = ast::make::path_concat(path, final_path) | ||
80 | } | ||
81 | Some(final_path) | ||
82 | } | ||
83 | |||
84 | #[cfg(test)] | ||
85 | mod tests { | ||
86 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
87 | |||
88 | use super::*; | ||
89 | |||
90 | #[test] | ||
91 | fn skip_single_use_item() { | ||
92 | mark::check!(skip_single_use_item); | ||
93 | check_assist_not_applicable( | ||
94 | unmerge_use, | ||
95 | r" | ||
96 | use std::fmt::Debug$0; | ||
97 | ", | ||
98 | ); | ||
99 | check_assist_not_applicable( | ||
100 | unmerge_use, | ||
101 | r" | ||
102 | use std::fmt::{Debug$0}; | ||
103 | ", | ||
104 | ); | ||
105 | check_assist_not_applicable( | ||
106 | unmerge_use, | ||
107 | r" | ||
108 | use std::fmt::Debug as Dbg$0; | ||
109 | ", | ||
110 | ); | ||
111 | } | ||
112 | |||
113 | #[test] | ||
114 | fn skip_single_glob_import() { | ||
115 | check_assist_not_applicable( | ||
116 | unmerge_use, | ||
117 | r" | ||
118 | use std::fmt::*$0; | ||
119 | ", | ||
120 | ); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn unmerge_use_item() { | ||
125 | check_assist( | ||
126 | unmerge_use, | ||
127 | r" | ||
128 | use std::fmt::{Debug, Display$0}; | ||
129 | ", | ||
130 | r" | ||
131 | use std::fmt::{Debug}; | ||
132 | use std::fmt::Display; | ||
133 | ", | ||
134 | ); | ||
135 | |||
136 | check_assist( | ||
137 | unmerge_use, | ||
138 | r" | ||
139 | use std::fmt::{Debug, format$0, Display}; | ||
140 | ", | ||
141 | r" | ||
142 | use std::fmt::{Debug, Display}; | ||
143 | use std::fmt::format; | ||
144 | ", | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn unmerge_glob_import() { | ||
150 | check_assist( | ||
151 | unmerge_use, | ||
152 | r" | ||
153 | use std::fmt::{*$0, Display}; | ||
154 | ", | ||
155 | r" | ||
156 | use std::fmt::{Display}; | ||
157 | use std::fmt::*; | ||
158 | ", | ||
159 | ); | ||
160 | } | ||
161 | |||
162 | #[test] | ||
163 | fn unmerge_renamed_use_item() { | ||
164 | check_assist( | ||
165 | unmerge_use, | ||
166 | r" | ||
167 | use std::fmt::{Debug, Display as Disp$0}; | ||
168 | ", | ||
169 | r" | ||
170 | use std::fmt::{Debug}; | ||
171 | use std::fmt::Display as Disp; | ||
172 | ", | ||
173 | ); | ||
174 | } | ||
175 | |||
176 | #[test] | ||
177 | fn unmerge_indented_use_item() { | ||
178 | check_assist( | ||
179 | unmerge_use, | ||
180 | r" | ||
181 | mod format { | ||
182 | use std::fmt::{Debug, Display$0 as Disp, format}; | ||
183 | } | ||
184 | ", | ||
185 | r" | ||
186 | mod format { | ||
187 | use std::fmt::{Debug, format}; | ||
188 | use std::fmt::Display as Disp; | ||
189 | } | ||
190 | ", | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn unmerge_nested_use_item() { | ||
196 | check_assist( | ||
197 | unmerge_use, | ||
198 | r" | ||
199 | use foo::bar::{baz::{qux$0, foobar}, barbaz}; | ||
200 | ", | ||
201 | r" | ||
202 | use foo::bar::{baz::{foobar}, barbaz}; | ||
203 | use foo::bar::baz::qux; | ||
204 | ", | ||
205 | ); | ||
206 | check_assist( | ||
207 | unmerge_use, | ||
208 | r" | ||
209 | use foo::bar::{baz$0::{qux, foobar}, barbaz}; | ||
210 | ", | ||
211 | r" | ||
212 | use foo::bar::{barbaz}; | ||
213 | use foo::bar::baz::{qux, foobar}; | ||
214 | ", | ||
215 | ); | ||
216 | } | ||
217 | |||
218 | #[test] | ||
219 | fn unmerge_use_item_with_visibility() { | ||
220 | check_assist( | ||
221 | unmerge_use, | ||
222 | r" | ||
223 | pub use std::fmt::{Debug, Display$0}; | ||
224 | ", | ||
225 | r" | ||
226 | pub use std::fmt::{Debug}; | ||
227 | pub use std::fmt::Display; | ||
228 | ", | ||
229 | ); | ||
230 | } | ||
231 | } | ||