aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/early_return.rs6
-rw-r--r--crates/ra_assists/src/handlers/expand_glob_import.rs391
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs5
-rw-r--r--crates/ra_assists/src/handlers/generate_function.rs2
-rw-r--r--crates/ra_assists/src/handlers/introduce_named_lifetime.rs2
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs2
-rw-r--r--crates/ra_assists/src/handlers/replace_if_let_with_match.rs2
-rw-r--r--crates/ra_assists/src/handlers/replace_let_with_if_let.rs4
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs42
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs4
10 files changed, 446 insertions, 14 deletions
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index 69852b611..6816a2709 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -123,7 +123,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
123 let happy_arm = { 123 let happy_arm = {
124 let pat = make::tuple_struct_pat( 124 let pat = make::tuple_struct_pat(
125 path, 125 path,
126 once(make::bind_pat(make::name("it")).into()), 126 once(make::ident_pat(make::name("it")).into()),
127 ); 127 );
128 let expr = { 128 let expr = {
129 let name_ref = make::name_ref("it"); 129 let name_ref = make::name_ref("it");
@@ -136,7 +136,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
136 136
137 let sad_arm = make::match_arm( 137 let sad_arm = make::match_arm(
138 // FIXME: would be cool to use `None` or `Err(_)` if appropriate 138 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
139 once(make::placeholder_pat().into()), 139 once(make::wildcard_pat().into()),
140 early_expression, 140 early_expression,
141 ); 141 );
142 142
@@ -144,7 +144,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
144 }; 144 };
145 145
146 let let_stmt = make::let_stmt( 146 let let_stmt = make::let_stmt(
147 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), 147 make::ident_pat(make::name(&bound_ident.syntax().to_string())).into(),
148 Some(match_expr), 148 Some(match_expr),
149 ); 149 );
150 let let_stmt = let_stmt.indent(if_indent_level); 150 let let_stmt = let_stmt.indent(if_indent_level);
diff --git a/crates/ra_assists/src/handlers/expand_glob_import.rs b/crates/ra_assists/src/handlers/expand_glob_import.rs
new file mode 100644
index 000000000..eb216a81a
--- /dev/null
+++ b/crates/ra_assists/src/handlers/expand_glob_import.rs
@@ -0,0 +1,391 @@
1use hir::{AssocItem, MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope};
2use ra_ide_db::{
3 defs::{classify_name_ref, Definition, NameRefClass},
4 RootDatabase,
5};
6use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T};
7
8use crate::{
9 assist_context::{AssistBuilder, AssistContext, Assists},
10 AssistId, AssistKind,
11};
12
13use either::Either;
14
15// Assist: expand_glob_import
16//
17// Expands glob imports.
18//
19// ```
20// mod foo {
21// pub struct Bar;
22// pub struct Baz;
23// }
24//
25// use foo::*<|>;
26//
27// fn qux(bar: Bar, baz: Baz) {}
28// ```
29// ->
30// ```
31// mod foo {
32// pub struct Bar;
33// pub struct Baz;
34// }
35//
36// use foo::{Baz, Bar};
37//
38// fn qux(bar: Bar, baz: Baz) {}
39// ```
40pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
41 let star = ctx.find_token_at_offset(T![*])?;
42 let mod_path = find_mod_path(&star)?;
43
44 let source_file = ctx.source_file();
45 let scope = ctx.sema.scope_at_offset(source_file.syntax(), ctx.offset());
46
47 let defs_in_mod = find_defs_in_mod(ctx, scope, &mod_path)?;
48 let name_refs_in_source_file =
49 source_file.syntax().descendants().filter_map(ast::NameRef::cast).collect();
50 let used_names = find_used_names(ctx, defs_in_mod, name_refs_in_source_file);
51
52 let parent = star.parent().parent()?;
53 acc.add(
54 AssistId("expand_glob_import", AssistKind::RefactorRewrite),
55 "Expand glob import",
56 parent.text_range(),
57 |builder| {
58 replace_ast(builder, &parent, mod_path, used_names);
59 },
60 )
61}
62
63fn find_mod_path(star: &SyntaxToken) -> Option<ast::Path> {
64 star.ancestors().find_map(|n| ast::UseTree::cast(n).and_then(|u| u.path()))
65}
66
67#[derive(PartialEq)]
68enum Def {
69 ModuleDef(ModuleDef),
70 MacroDef(MacroDef),
71}
72
73impl Def {
74 fn name(&self, db: &RootDatabase) -> Option<Name> {
75 match self {
76 Def::ModuleDef(def) => def.name(db),
77 Def::MacroDef(def) => def.name(db),
78 }
79 }
80}
81
82fn find_defs_in_mod(
83 ctx: &AssistContext,
84 from: SemanticsScope<'_>,
85 path: &ast::Path,
86) -> Option<Vec<Def>> {
87 let hir_path = ctx.sema.lower_path(&path)?;
88 let module = if let Some(PathResolution::Def(ModuleDef::Module(module))) =
89 from.resolve_hir_path_qualifier(&hir_path)
90 {
91 module
92 } else {
93 return None;
94 };
95
96 let module_scope = module.scope(ctx.db(), from.module());
97
98 let mut defs = vec![];
99 for (_, def) in module_scope {
100 match def {
101 ScopeDef::ModuleDef(def) => defs.push(Def::ModuleDef(def)),
102 ScopeDef::MacroDef(def) => defs.push(Def::MacroDef(def)),
103 _ => continue,
104 }
105 }
106
107 Some(defs)
108}
109
110fn find_used_names(
111 ctx: &AssistContext,
112 defs_in_mod: Vec<Def>,
113 name_refs_in_source_file: Vec<ast::NameRef>,
114) -> Vec<Name> {
115 let defs_in_source_file = name_refs_in_source_file
116 .iter()
117 .filter_map(|r| classify_name_ref(&ctx.sema, r))
118 .filter_map(|rc| match rc {
119 NameRefClass::Definition(Definition::ModuleDef(def)) => Some(Def::ModuleDef(def)),
120 NameRefClass::Definition(Definition::Macro(def)) => Some(Def::MacroDef(def)),
121 _ => None,
122 })
123 .collect::<Vec<Def>>();
124
125 defs_in_mod
126 .iter()
127 .filter(|def| {
128 if let Def::ModuleDef(ModuleDef::Trait(tr)) = def {
129 for item in tr.items(ctx.db()) {
130 if let AssocItem::Function(f) = item {
131 if defs_in_source_file.contains(&Def::ModuleDef(ModuleDef::Function(f))) {
132 return true;
133 }
134 }
135 }
136 }
137
138 defs_in_source_file.contains(def)
139 })
140 .filter_map(|d| d.name(ctx.db()))
141 .collect()
142}
143
144fn replace_ast(
145 builder: &mut AssistBuilder,
146 node: &SyntaxNode,
147 path: ast::Path,
148 used_names: Vec<Name>,
149) {
150 let replacement: Either<ast::UseTree, ast::UseTreeList> = match used_names.as_slice() {
151 [name] => Either::Left(ast::make::use_tree(
152 ast::make::path_from_text(&format!("{}::{}", path, name)),
153 None,
154 None,
155 false,
156 )),
157 names => Either::Right(ast::make::use_tree_list(names.iter().map(|n| {
158 ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false)
159 }))),
160 };
161
162 let mut replace_node = |replacement: Either<ast::UseTree, ast::UseTreeList>| {
163 algo::diff(node, &replacement.either(|u| u.syntax().clone(), |ut| ut.syntax().clone()))
164 .into_text_edit(builder.text_edit_builder());
165 };
166
167 match_ast! {
168 match node {
169 ast::UseTree(use_tree) => {
170 replace_node(replacement);
171 },
172 ast::UseTreeList(use_tree_list) => {
173 replace_node(replacement);
174 },
175 ast::Use(use_item) => {
176 builder.replace_ast(use_item, ast::make::use_(replacement.left_or_else(|ut| ast::make::use_tree(path, Some(ut), None, false))));
177 },
178 _ => {},
179 }
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use crate::tests::{check_assist, check_assist_not_applicable};
186
187 use super::*;
188
189 #[test]
190 fn expanding_glob_import() {
191 check_assist(
192 expand_glob_import,
193 r"
194mod foo {
195 pub struct Bar;
196 pub struct Baz;
197 pub struct Qux;
198
199 pub fn f() {}
200}
201
202use foo::*<|>;
203
204fn qux(bar: Bar, baz: Baz) {
205 f();
206}
207",
208 r"
209mod foo {
210 pub struct Bar;
211 pub struct Baz;
212 pub struct Qux;
213
214 pub fn f() {}
215}
216
217use foo::{Baz, Bar, f};
218
219fn qux(bar: Bar, baz: Baz) {
220 f();
221}
222",
223 )
224 }
225
226 #[test]
227 fn expanding_glob_import_with_existing_explicit_names() {
228 check_assist(
229 expand_glob_import,
230 r"
231mod foo {
232 pub struct Bar;
233 pub struct Baz;
234 pub struct Qux;
235
236 pub fn f() {}
237}
238
239use foo::{*<|>, f};
240
241fn qux(bar: Bar, baz: Baz) {
242 f();
243}
244",
245 r"
246mod foo {
247 pub struct Bar;
248 pub struct Baz;
249 pub struct Qux;
250
251 pub fn f() {}
252}
253
254use foo::{Baz, Bar, f};
255
256fn qux(bar: Bar, baz: Baz) {
257 f();
258}
259",
260 )
261 }
262
263 #[test]
264 fn expanding_nested_glob_import() {
265 check_assist(
266 expand_glob_import,
267 r"
268mod foo {
269 mod bar {
270 pub struct Bar;
271 pub struct Baz;
272 pub struct Qux;
273
274 pub fn f() {}
275 }
276
277 mod baz {
278 pub fn g() {}
279 }
280}
281
282use foo::{bar::{*<|>, f}, baz::*};
283
284fn qux(bar: Bar, baz: Baz) {
285 f();
286 g();
287}
288",
289 r"
290mod foo {
291 mod bar {
292 pub struct Bar;
293 pub struct Baz;
294 pub struct Qux;
295
296 pub fn f() {}
297 }
298
299 mod baz {
300 pub fn g() {}
301 }
302}
303
304use foo::{bar::{Baz, Bar, f}, baz::*};
305
306fn qux(bar: Bar, baz: Baz) {
307 f();
308 g();
309}
310",
311 )
312 }
313
314 #[test]
315 fn expanding_glob_import_with_macro_defs() {
316 check_assist(
317 expand_glob_import,
318 r"
319//- /lib.rs crate:foo
320#[macro_export]
321macro_rules! bar {
322 () => ()
323}
324
325pub fn baz() {}
326
327//- /main.rs crate:main deps:foo
328use foo::*<|>;
329
330fn main() {
331 bar!();
332 baz();
333}
334",
335 r"
336use foo::{bar, baz};
337
338fn main() {
339 bar!();
340 baz();
341}
342",
343 )
344 }
345
346 #[test]
347 fn expanding_glob_import_with_trait_method_uses() {
348 check_assist(
349 expand_glob_import,
350 r"
351//- /lib.rs crate:foo
352pub trait Tr {
353 fn method(&self) {}
354}
355impl Tr for () {}
356
357//- /main.rs crate:main deps:foo
358use foo::*<|>;
359
360fn main() {
361 ().method();
362}
363",
364 r"
365use foo::Tr;
366
367fn main() {
368 ().method();
369}
370",
371 )
372 }
373
374 #[test]
375 fn expanding_is_not_applicable_if_cursor_is_not_in_star_token() {
376 check_assist_not_applicable(
377 expand_glob_import,
378 r"
379 mod foo {
380 pub struct Bar;
381 pub struct Baz;
382 pub struct Qux;
383 }
384
385 use foo::Bar<|>;
386
387 fn qux(bar: Bar, baz: Baz) {}
388 ",
389 )
390 }
391}
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index b2e14f9d7..6698d1a27 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -197,12 +197,11 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O
197 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though 197 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
198 let pat: ast::Pat = match var.source(db).value.kind() { 198 let pat: ast::Pat = match var.source(db).value.kind() {
199 ast::StructKind::Tuple(field_list) => { 199 ast::StructKind::Tuple(field_list) => {
200 let pats = 200 let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
201 iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count());
202 make::tuple_struct_pat(path, pats).into() 201 make::tuple_struct_pat(path, pats).into()
203 } 202 }
204 ast::StructKind::Record(field_list) => { 203 ast::StructKind::Record(field_list) => {
205 let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); 204 let pats = field_list.fields().map(|f| make::ident_pat(f.name().unwrap()).into());
206 make::record_pat(path, pats).into() 205 make::record_pat(path, pats).into()
207 } 206 }
208 ast::StructKind::Unit => make::path_pat(path), 207 ast::StructKind::Unit => make::path_pat(path),
diff --git a/crates/ra_assists/src/handlers/generate_function.rs b/crates/ra_assists/src/handlers/generate_function.rs
index 56510861d..acc97e648 100644
--- a/crates/ra_assists/src/handlers/generate_function.rs
+++ b/crates/ra_assists/src/handlers/generate_function.rs
@@ -142,7 +142,7 @@ impl FunctionBuilder {
142 let fn_body = make::block_expr(vec![], Some(placeholder_expr)); 142 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
143 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; 143 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
144 let mut fn_def = 144 let mut fn_def =
145 make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body); 145 make::fn_(visibility, self.fn_name, self.type_params, self.params, fn_body);
146 let leading_ws; 146 let leading_ws;
147 let trailing_ws; 147 let trailing_ws;
148 148
diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs
index 4537c73a1..fbaf3c06b 100644
--- a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs
@@ -68,7 +68,7 @@ fn generate_fn_def_assist(
68 let fn_params_without_lifetime: Vec<_> = param_list 68 let fn_params_without_lifetime: Vec<_> = param_list
69 .params() 69 .params()
70 .filter_map(|param| match param.ty() { 70 .filter_map(|param| match param.ty() {
71 Some(ast::Type::ReferenceType(ascribed_type)) 71 Some(ast::Type::RefType(ascribed_type))
72 if ascribed_type.lifetime_token() == None => 72 if ascribed_type.lifetime_token() == None =>
73 { 73 {
74 Some(ascribed_type.amp_token()?.text_range().end()) 74 Some(ascribed_type.amp_token()?.text_range().end())
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index 4e8a0c2db..4c797178f 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -173,7 +173,7 @@ fn test_required_hashes() {
173} 173}
174 174
175#[cfg(test)] 175#[cfg(test)]
176mod test { 176mod tests {
177 use test_utils::mark; 177 use test_utils::mark;
178 178
179 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; 179 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index b7e30a7f2..ecafb74a1 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -65,7 +65,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
65 .type_of_pat(&pat) 65 .type_of_pat(&pat)
66 .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty)) 66 .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty))
67 .map(|it| it.sad_pattern()) 67 .map(|it| it.sad_pattern())
68 .unwrap_or_else(|| make::placeholder_pat().into()); 68 .unwrap_or_else(|| make::wildcard_pat().into());
69 let else_expr = unwrap_trivial_block(else_block); 69 let else_expr = unwrap_trivial_block(else_block);
70 make::match_arm(vec![pattern], else_expr) 70 make::match_arm(vec![pattern], else_expr)
71 }; 71 };
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
index 64ad15a23..e4d436dec 100644
--- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
@@ -50,10 +50,10 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
50 target, 50 target,
51 |edit| { 51 |edit| {
52 let with_placeholder: ast::Pat = match happy_variant { 52 let with_placeholder: ast::Pat = match happy_variant {
53 None => make::placeholder_pat().into(), 53 None => make::wildcard_pat().into(),
54 Some(var_name) => make::tuple_struct_pat( 54 Some(var_name) => make::tuple_struct_pat(
55 make::path_unqualified(make::path_segment(make::name_ref(var_name))), 55 make::path_unqualified(make::path_segment(make::name_ref(var_name))),
56 once(make::placeholder_pat().into()), 56 once(make::wildcard_pat().into()),
57 ) 57 )
58 .into(), 58 .into(),
59 }; 59 };
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index 53496ede1..da0a860c5 100644
--- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -643,4 +643,46 @@ fn main() {
643 ", 643 ",
644 ); 644 );
645 } 645 }
646
647 #[test]
648 fn does_not_replace_pub_use() {
649 check_assist(
650 replace_qualified_name_with_use,
651 r"
652pub use std::fmt;
653
654impl std::io<|> for Foo {
655}
656 ",
657 r"
658use std::io;
659
660pub use std::fmt;
661
662impl io for Foo {
663}
664 ",
665 );
666 }
667
668 #[test]
669 fn does_not_replace_pub_crate_use() {
670 check_assist(
671 replace_qualified_name_with_use,
672 r"
673pub(crate) use std::fmt;
674
675impl std::io<|> for Foo {
676}
677 ",
678 r"
679use std::io;
680
681pub(crate) use std::fmt;
682
683impl io for Foo {
684}
685 ",
686 );
687 }
646} 688}
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
index e5a4bb23c..d69f2c1b0 100644
--- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -52,7 +52,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
52 target, 52 target,
53 |builder| { 53 |builder| {
54 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); 54 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
55 let it = make::bind_pat(make::name("a")).into(); 55 let it = make::ident_pat(make::name("a")).into();
56 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); 56 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
57 57
58 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); 58 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
@@ -60,7 +60,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
60 60
61 let unreachable_call = make::expr_unreachable(); 61 let unreachable_call = make::expr_unreachable();
62 let err_arm = 62 let err_arm =
63 make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); 63 make::match_arm(iter::once(make::wildcard_pat().into()), unreachable_call);
64 64
65 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); 65 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
66 let match_expr = make::expr_match(caller.clone(), match_arm_list) 66 let match_expr = make::expr_match(caller.clone(), match_arm_list)