aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/add_function.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/add_function.rs')
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs355
1 files changed, 219 insertions, 136 deletions
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index 6c7456579..24f931a85 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -1,13 +1,21 @@
1use hir::HirDisplay;
2use ra_db::FileId;
1use ra_syntax::{ 3use ra_syntax::{
2 ast::{self, AstNode}, 4 ast::{
5 self,
6 edit::{AstNodeEdit, IndentLevel},
7 make, ArgListOwner, AstNode, ModuleItemOwner,
8 },
3 SyntaxKind, SyntaxNode, TextSize, 9 SyntaxKind, SyntaxNode, TextSize,
4}; 10};
5
6use crate::{Assist, AssistCtx, AssistFile, AssistId};
7use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner};
8use hir::HirDisplay;
9use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap, FxHashSet};
10 12
13use crate::{
14 assist_config::SnippetCap,
15 utils::{render_snippet, Cursor},
16 AssistContext, AssistId, Assists,
17};
18
11// Assist: add_function 19// Assist: add_function
12// 20//
13// Adds a stub function with a signature matching the function under the cursor. 21// Adds a stub function with a signature matching the function under the cursor.
@@ -29,11 +37,11 @@ use rustc_hash::{FxHashMap, FxHashSet};
29// } 37// }
30// 38//
31// fn bar(arg: &str, baz: Baz) { 39// fn bar(arg: &str, baz: Baz) {
32// todo!() 40// ${0:todo!()}
33// } 41// }
34// 42//
35// ``` 43// ```
36pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { 44pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
37 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; 45 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
38 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; 46 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
39 let path = path_expr.path()?; 47 let path = path_expr.path()?;
@@ -43,36 +51,49 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
43 return None; 51 return None;
44 } 52 }
45 53
46 let target_module = if let Some(qualifier) = path.qualifier() { 54 let target_module = match path.qualifier() {
47 if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = 55 Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
48 ctx.sema.resolve_path(&qualifier) 56 Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => Some(module),
49 { 57 _ => return None,
50 Some(module.definition_source(ctx.sema.db)) 58 },
51 } else { 59 None => None,
52 return None;
53 }
54 } else {
55 None
56 }; 60 };
57 61
58 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; 62 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
59 63
60 ctx.add_assist(AssistId("add_function"), "Add function", |edit| { 64 let target = call.syntax().text_range();
61 edit.target(call.syntax().text_range()); 65 acc.add(AssistId("add_function"), "Add function", target, |builder| {
62 66 let function_template = function_builder.render();
63 if let Some(function_template) = function_builder.render() { 67 builder.set_file(function_template.file);
64 edit.set_file(function_template.file); 68 let new_fn = function_template.to_string(ctx.config.snippet_cap);
65 edit.set_cursor(function_template.cursor_offset); 69 match ctx.config.snippet_cap {
66 edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); 70 Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
71 None => builder.insert(function_template.insert_offset, new_fn),
67 } 72 }
68 }) 73 })
69} 74}
70 75
71struct FunctionTemplate { 76struct FunctionTemplate {
72 insert_offset: TextSize, 77 insert_offset: TextSize,
73 cursor_offset: TextSize, 78 placeholder_expr: ast::MacroCall,
74 fn_def: ast::SourceFile, 79 leading_ws: String,
75 file: AssistFile, 80 fn_def: ast::FnDef,
81 trailing_ws: String,
82 file: FileId,
83}
84
85impl FunctionTemplate {
86 fn to_string(&self, cap: Option<SnippetCap>) -> String {
87 let f = match cap {
88 Some(cap) => render_snippet(
89 cap,
90 self.fn_def.syntax(),
91 Cursor::Replace(self.placeholder_expr.syntax()),
92 ),
93 None => self.fn_def.to_string(),
94 };
95 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
96 }
76} 97}
77 98
78struct FunctionBuilder { 99struct FunctionBuilder {
@@ -80,68 +101,73 @@ struct FunctionBuilder {
80 fn_name: ast::Name, 101 fn_name: ast::Name,
81 type_params: Option<ast::TypeParamList>, 102 type_params: Option<ast::TypeParamList>,
82 params: ast::ParamList, 103 params: ast::ParamList,
83 file: AssistFile, 104 file: FileId,
84 needs_pub: bool, 105 needs_pub: bool,
85} 106}
86 107
87impl FunctionBuilder { 108impl FunctionBuilder {
88 /// Prepares a generated function that matches `call` in `generate_in` 109 /// Prepares a generated function that matches `call`.
89 /// (or as close to `call` as possible, if `generate_in` is `None`) 110 /// The function is generated in `target_module` or next to `call`
90 fn from_call( 111 fn from_call(
91 ctx: &AssistCtx, 112 ctx: &AssistContext,
92 call: &ast::CallExpr, 113 call: &ast::CallExpr,
93 path: &ast::Path, 114 path: &ast::Path,
94 target_module: Option<hir::InFile<hir::ModuleSource>>, 115 target_module: Option<hir::Module>,
95 ) -> Option<Self> { 116 ) -> Option<Self> {
96 let needs_pub = target_module.is_some(); 117 let mut file = ctx.frange.file_id;
97 let mut file = AssistFile::default(); 118 let target = match &target_module {
98 let target = if let Some(target_module) = target_module { 119 Some(target_module) => {
99 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, target_module)?; 120 let module_source = target_module.definition_source(ctx.db);
100 file = in_file; 121 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
101 target 122 file = in_file;
102 } else { 123 target
103 next_space_for_fn_after_call_site(&call)? 124 }
125 None => next_space_for_fn_after_call_site(&call)?,
104 }; 126 };
127 let needs_pub = target_module.is_some();
128 let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?;
105 let fn_name = fn_name(&path)?; 129 let fn_name = fn_name(&path)?;
106 let (type_params, params) = fn_args(ctx, &call)?; 130 let (type_params, params) = fn_args(ctx, target_module, &call)?;
131
107 Some(Self { target, fn_name, type_params, params, file, needs_pub }) 132 Some(Self { target, fn_name, type_params, params, file, needs_pub })
108 } 133 }
109 134
110 fn render(self) -> Option<FunctionTemplate> { 135 fn render(self) -> FunctionTemplate {
111 let placeholder_expr = ast::make::expr_todo(); 136 let placeholder_expr = make::expr_todo();
112 let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); 137 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
113 let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); 138 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
114 if self.needs_pub { 139 let mut fn_def =
115 fn_def = ast::make::add_pub_crate_modifier(fn_def); 140 make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body);
116 } 141 let leading_ws;
142 let trailing_ws;
117 143
118 let (fn_def, insert_offset) = match self.target { 144 let insert_offset = match self.target {
119 GeneratedFunctionTarget::BehindItem(it) => { 145 GeneratedFunctionTarget::BehindItem(it) => {
120 let with_leading_blank_line = ast::make::add_leading_newlines(2, fn_def); 146 let indent = IndentLevel::from_node(&it);
121 let indented = IndentLevel::from_node(&it).increase_indent(with_leading_blank_line); 147 leading_ws = format!("\n\n{}", indent);
122 (indented, it.text_range().end()) 148 fn_def = fn_def.indent(indent);
149 trailing_ws = String::new();
150 it.text_range().end()
123 } 151 }
124 GeneratedFunctionTarget::InEmptyItemList(it) => { 152 GeneratedFunctionTarget::InEmptyItemList(it) => {
125 let indent_once = IndentLevel(1);
126 let indent = IndentLevel::from_node(it.syntax()); 153 let indent = IndentLevel::from_node(it.syntax());
127 154 leading_ws = format!("\n{}", indent + 1);
128 let fn_def = ast::make::add_leading_newlines(1, fn_def); 155 fn_def = fn_def.indent(indent + 1);
129 let fn_def = indent_once.increase_indent(fn_def); 156 trailing_ws = format!("\n{}", indent);
130 let fn_def = ast::make::add_trailing_newlines(1, fn_def); 157 it.syntax().text_range().start() + TextSize::of('{')
131 let fn_def = indent.increase_indent(fn_def);
132 (fn_def, it.syntax().text_range().start() + TextSize::of('{'))
133 } 158 }
134 }; 159 };
135 160
136 let cursor_offset_from_fn_start = fn_def 161 let placeholder_expr =
137 .syntax() 162 fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
138 .descendants() 163 FunctionTemplate {
139 .find_map(ast::MacroCall::cast)? 164 insert_offset,
140 .syntax() 165 placeholder_expr,
141 .text_range() 166 leading_ws,
142 .start(); 167 fn_def,
143 let cursor_offset = insert_offset + cursor_offset_from_fn_start; 168 trailing_ws,
144 Some(FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file }) 169 file: self.file,
170 }
145 } 171 }
146} 172}
147 173
@@ -150,32 +176,41 @@ enum GeneratedFunctionTarget {
150 InEmptyItemList(ast::ItemList), 176 InEmptyItemList(ast::ItemList),
151} 177}
152 178
179impl GeneratedFunctionTarget {
180 fn syntax(&self) -> &SyntaxNode {
181 match self {
182 GeneratedFunctionTarget::BehindItem(it) => it,
183 GeneratedFunctionTarget::InEmptyItemList(it) => it.syntax(),
184 }
185 }
186}
187
153fn fn_name(call: &ast::Path) -> Option<ast::Name> { 188fn fn_name(call: &ast::Path) -> Option<ast::Name> {
154 let name = call.segment()?.syntax().to_string(); 189 let name = call.segment()?.syntax().to_string();
155 Some(ast::make::name(&name)) 190 Some(make::name(&name))
156} 191}
157 192
158/// Computes the type variables and arguments required for the generated function 193/// Computes the type variables and arguments required for the generated function
159fn fn_args( 194fn fn_args(
160 ctx: &AssistCtx, 195 ctx: &AssistContext,
196 target_module: hir::Module,
161 call: &ast::CallExpr, 197 call: &ast::CallExpr,
162) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> { 198) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> {
163 let mut arg_names = Vec::new(); 199 let mut arg_names = Vec::new();
164 let mut arg_types = Vec::new(); 200 let mut arg_types = Vec::new();
165 for arg in call.arg_list()?.args() { 201 for arg in call.arg_list()?.args() {
166 let arg_name = match fn_arg_name(&arg) { 202 arg_names.push(match fn_arg_name(&arg) {
167 Some(name) => name, 203 Some(name) => name,
168 None => String::from("arg"), 204 None => String::from("arg"),
169 }; 205 });
170 arg_names.push(arg_name); 206 arg_types.push(match fn_arg_type(ctx, target_module, &arg) {
171 arg_types.push(match fn_arg_type(ctx, &arg) {
172 Some(ty) => ty, 207 Some(ty) => ty,
173 None => String::from("()"), 208 None => String::from("()"),
174 }); 209 });
175 } 210 }
176 deduplicate_arg_names(&mut arg_names); 211 deduplicate_arg_names(&mut arg_names);
177 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| ast::make::param(name, ty)); 212 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| make::param(name, ty));
178 Some((None, ast::make::param_list(params))) 213 Some((None, make::param_list(params)))
179} 214}
180 215
181/// Makes duplicate argument names unique by appending incrementing numbers. 216/// Makes duplicate argument names unique by appending incrementing numbers.
@@ -224,12 +259,21 @@ fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
224 } 259 }
225} 260}
226 261
227fn fn_arg_type(ctx: &AssistCtx, fn_arg: &ast::Expr) -> Option<String> { 262fn fn_arg_type(
263 ctx: &AssistContext,
264 target_module: hir::Module,
265 fn_arg: &ast::Expr,
266) -> Option<String> {
228 let ty = ctx.sema.type_of_expr(fn_arg)?; 267 let ty = ctx.sema.type_of_expr(fn_arg)?;
229 if ty.is_unknown() { 268 if ty.is_unknown() {
230 return None; 269 return None;
231 } 270 }
232 Some(ty.display(ctx.sema.db).to_string()) 271
272 if let Ok(rendered) = ty.display_source_code(ctx.db, target_module.into()) {
273 Some(rendered)
274 } else {
275 None
276 }
233} 277}
234 278
235/// Returns the position inside the current mod or file 279/// Returns the position inside the current mod or file
@@ -258,11 +302,10 @@ fn next_space_for_fn_after_call_site(expr: &ast::CallExpr) -> Option<GeneratedFu
258 302
259fn next_space_for_fn_in_module( 303fn next_space_for_fn_in_module(
260 db: &dyn hir::db::AstDatabase, 304 db: &dyn hir::db::AstDatabase,
261 module: hir::InFile<hir::ModuleSource>, 305 module_source: &hir::InFile<hir::ModuleSource>,
262) -> Option<(AssistFile, GeneratedFunctionTarget)> { 306) -> Option<(FileId, GeneratedFunctionTarget)> {
263 let file = module.file_id.original_file(db); 307 let file = module_source.file_id.original_file(db);
264 let assist_file = AssistFile::TargetFile(file); 308 let assist_item = match &module_source.value {
265 let assist_item = match module.value {
266 hir::ModuleSource::SourceFile(it) => { 309 hir::ModuleSource::SourceFile(it) => {
267 if let Some(last_item) = it.items().last() { 310 if let Some(last_item) = it.items().last() {
268 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) 311 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
@@ -278,12 +321,12 @@ fn next_space_for_fn_in_module(
278 } 321 }
279 } 322 }
280 }; 323 };
281 Some((assist_file, assist_item)) 324 Some((file, assist_item))
282} 325}
283 326
284#[cfg(test)] 327#[cfg(test)]
285mod tests { 328mod tests {
286 use crate::helpers::{check_assist, check_assist_not_applicable}; 329 use crate::tests::{check_assist, check_assist_not_applicable};
287 330
288 use super::*; 331 use super::*;
289 332
@@ -302,7 +345,7 @@ fn foo() {
302} 345}
303 346
304fn bar() { 347fn bar() {
305 <|>todo!() 348 ${0:todo!()}
306} 349}
307", 350",
308 ) 351 )
@@ -329,7 +372,7 @@ impl Foo {
329} 372}
330 373
331fn bar() { 374fn bar() {
332 <|>todo!() 375 ${0:todo!()}
333} 376}
334", 377",
335 ) 378 )
@@ -353,7 +396,7 @@ fn foo1() {
353} 396}
354 397
355fn bar() { 398fn bar() {
356 <|>todo!() 399 ${0:todo!()}
357} 400}
358 401
359fn foo2() {} 402fn foo2() {}
@@ -379,7 +422,7 @@ mod baz {
379 } 422 }
380 423
381 fn bar() { 424 fn bar() {
382 <|>todo!() 425 ${0:todo!()}
383 } 426 }
384} 427}
385", 428",
@@ -405,7 +448,7 @@ fn foo() {
405} 448}
406 449
407fn bar(baz: Baz) { 450fn bar(baz: Baz) {
408 <|>todo!() 451 ${0:todo!()}
409} 452}
410", 453",
411 ); 454 );
@@ -438,7 +481,7 @@ impl Baz {
438} 481}
439 482
440fn bar(baz: Baz) { 483fn bar(baz: Baz) {
441 <|>todo!() 484 ${0:todo!()}
442} 485}
443", 486",
444 ) 487 )
@@ -459,7 +502,7 @@ fn foo() {
459} 502}
460 503
461fn bar(arg: &str) { 504fn bar(arg: &str) {
462 <|>todo!() 505 ${0:todo!()}
463} 506}
464"#, 507"#,
465 ) 508 )
@@ -480,7 +523,7 @@ fn foo() {
480} 523}
481 524
482fn bar(arg: char) { 525fn bar(arg: char) {
483 <|>todo!() 526 ${0:todo!()}
484} 527}
485"#, 528"#,
486 ) 529 )
@@ -501,7 +544,7 @@ fn foo() {
501} 544}
502 545
503fn bar(arg: i32) { 546fn bar(arg: i32) {
504 <|>todo!() 547 ${0:todo!()}
505} 548}
506", 549",
507 ) 550 )
@@ -522,7 +565,7 @@ fn foo() {
522} 565}
523 566
524fn bar(arg: u8) { 567fn bar(arg: u8) {
525 <|>todo!() 568 ${0:todo!()}
526} 569}
527", 570",
528 ) 571 )
@@ -547,7 +590,7 @@ fn foo() {
547} 590}
548 591
549fn bar(x: u8) { 592fn bar(x: u8) {
550 <|>todo!() 593 ${0:todo!()}
551} 594}
552", 595",
553 ) 596 )
@@ -570,7 +613,7 @@ fn foo() {
570} 613}
571 614
572fn bar(worble: ()) { 615fn bar(worble: ()) {
573 <|>todo!() 616 ${0:todo!()}
574} 617}
575", 618",
576 ) 619 )
@@ -599,15 +642,40 @@ fn baz() {
599} 642}
600 643
601fn bar(foo: impl Foo) { 644fn bar(foo: impl Foo) {
602 <|>todo!() 645 ${0:todo!()}
646}
647",
648 )
649 }
650
651 #[test]
652 fn borrowed_arg() {
653 check_assist(
654 add_function,
655 r"
656struct Baz;
657fn baz() -> Baz { todo!() }
658
659fn foo() {
660 bar<|>(&baz())
661}
662",
663 r"
664struct Baz;
665fn baz() -> Baz { todo!() }
666
667fn foo() {
668 bar(&baz())
669}
670
671fn bar(baz: &Baz) {
672 ${0:todo!()}
603} 673}
604", 674",
605 ) 675 )
606 } 676 }
607 677
608 #[test] 678 #[test]
609 #[ignore]
610 // FIXME print paths properly to make this test pass
611 fn add_function_with_qualified_path_arg() { 679 fn add_function_with_qualified_path_arg() {
612 check_assist( 680 check_assist(
613 add_function, 681 add_function,
@@ -616,10 +684,8 @@ mod Baz {
616 pub struct Bof; 684 pub struct Bof;
617 pub fn baz() -> Bof { Bof } 685 pub fn baz() -> Bof { Bof }
618} 686}
619mod Foo { 687fn foo() {
620 fn foo() { 688 <|>bar(Baz::baz())
621 <|>bar(super::Baz::baz())
622 }
623} 689}
624", 690",
625 r" 691 r"
@@ -627,14 +693,12 @@ mod Baz {
627 pub struct Bof; 693 pub struct Bof;
628 pub fn baz() -> Bof { Bof } 694 pub fn baz() -> Bof { Bof }
629} 695}
630mod Foo { 696fn foo() {
631 fn foo() { 697 bar(Baz::baz())
632 bar(super::Baz::baz()) 698}
633 }
634 699
635 fn bar(baz: super::Baz::Bof) { 700fn bar(baz: Baz::Bof) {
636 <|>todo!() 701 ${0:todo!()}
637 }
638} 702}
639", 703",
640 ) 704 )
@@ -657,7 +721,7 @@ fn foo<T>(t: T) {
657} 721}
658 722
659fn bar<T>(t: T) { 723fn bar<T>(t: T) {
660 <|>todo!() 724 ${0:todo!()}
661} 725}
662", 726",
663 ) 727 )
@@ -688,7 +752,7 @@ fn foo() {
688} 752}
689 753
690fn bar(arg: fn() -> Baz) { 754fn bar(arg: fn() -> Baz) {
691 <|>todo!() 755 ${0:todo!()}
692} 756}
693", 757",
694 ) 758 )
@@ -713,7 +777,7 @@ fn foo() {
713} 777}
714 778
715fn bar(closure: impl Fn(i64) -> i64) { 779fn bar(closure: impl Fn(i64) -> i64) {
716 <|>todo!() 780 ${0:todo!()}
717} 781}
718", 782",
719 ) 783 )
@@ -734,7 +798,7 @@ fn foo() {
734} 798}
735 799
736fn bar(baz: ()) { 800fn bar(baz: ()) {
737 <|>todo!() 801 ${0:todo!()}
738} 802}
739", 803",
740 ) 804 )
@@ -759,7 +823,7 @@ fn foo() {
759} 823}
760 824
761fn bar(baz_1: Baz, baz_2: Baz) { 825fn bar(baz_1: Baz, baz_2: Baz) {
762 <|>todo!() 826 ${0:todo!()}
763} 827}
764", 828",
765 ) 829 )
@@ -784,7 +848,7 @@ fn foo() {
784} 848}
785 849
786fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { 850fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
787 <|>todo!() 851 ${0:todo!()}
788} 852}
789"#, 853"#,
790 ) 854 )
@@ -804,7 +868,7 @@ fn foo() {
804 r" 868 r"
805mod bar { 869mod bar {
806 pub(crate) fn my_fn() { 870 pub(crate) fn my_fn() {
807 <|>todo!() 871 ${0:todo!()}
808 } 872 }
809} 873}
810 874
@@ -816,6 +880,40 @@ fn foo() {
816 } 880 }
817 881
818 #[test] 882 #[test]
883 #[ignore]
884 // Ignored until local imports are supported.
885 // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
886 fn qualified_path_uses_correct_scope() {
887 check_assist(
888 add_function,
889 "
890mod foo {
891 pub struct Foo;
892}
893fn bar() {
894 use foo::Foo;
895 let foo = Foo;
896 baz<|>(foo)
897}
898",
899 "
900mod foo {
901 pub struct Foo;
902}
903fn bar() {
904 use foo::Foo;
905 let foo = Foo;
906 baz(foo)
907}
908
909fn baz(foo: foo::Foo) {
910 ${0:todo!()}
911}
912",
913 )
914 }
915
916 #[test]
819 fn add_function_in_module_containing_other_items() { 917 fn add_function_in_module_containing_other_items() {
820 check_assist( 918 check_assist(
821 add_function, 919 add_function,
@@ -833,7 +931,7 @@ mod bar {
833 fn something_else() {} 931 fn something_else() {}
834 932
835 pub(crate) fn my_fn() { 933 pub(crate) fn my_fn() {
836 <|>todo!() 934 ${0:todo!()}
837 } 935 }
838} 936}
839 937
@@ -861,7 +959,7 @@ fn foo() {
861mod bar { 959mod bar {
862 mod baz { 960 mod baz {
863 pub(crate) fn my_fn() { 961 pub(crate) fn my_fn() {
864 <|>todo!() 962 ${0:todo!()}
865 } 963 }
866 } 964 }
867} 965}
@@ -890,7 +988,7 @@ fn main() {
890 988
891 989
892pub(crate) fn bar() { 990pub(crate) fn bar() {
893 <|>todo!() 991 ${0:todo!()}
894}", 992}",
895 ) 993 )
896 } 994 }
@@ -927,21 +1025,6 @@ fn bar(baz: ()) {}
927 } 1025 }
928 1026
929 #[test] 1027 #[test]
930 fn add_function_not_applicable_if_function_path_not_singleton() {
931 // In the future this assist could be extended to generate functions
932 // if the path is in the same crate (or even the same workspace).
933 // For the beginning, I think this is fine.
934 check_assist_not_applicable(
935 add_function,
936 r"
937fn foo() {
938 other_crate::bar<|>();
939}
940 ",
941 )
942 }
943
944 #[test]
945 #[ignore] 1028 #[ignore]
946 fn create_method_with_no_args() { 1029 fn create_method_with_no_args() {
947 check_assist( 1030 check_assist(