aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/generate_function.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers/generate_function.rs')
-rw-r--r--crates/assists/src/handlers/generate_function.rs1059
1 files changed, 0 insertions, 1059 deletions
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
deleted file mode 100644
index 06ac85f67..000000000
--- a/crates/assists/src/handlers/generate_function.rs
+++ /dev/null
@@ -1,1059 +0,0 @@
1use hir::HirDisplay;
2use ide_db::{base_db::FileId, helpers::SnippetCap};
3use rustc_hash::{FxHashMap, FxHashSet};
4use syntax::{
5 ast::{
6 self,
7 edit::{AstNodeEdit, IndentLevel},
8 make, ArgListOwner, AstNode, ModuleItemOwner,
9 },
10 SyntaxKind, SyntaxNode, TextSize,
11};
12
13use crate::{
14 utils::{render_snippet, Cursor},
15 AssistContext, AssistId, AssistKind, Assists,
16};
17
18// Assist: generate_function
19//
20// Adds a stub function with a signature matching the function under the cursor.
21//
22// ```
23// struct Baz;
24// fn baz() -> Baz { Baz }
25// fn foo() {
26// bar$0("", baz());
27// }
28//
29// ```
30// ->
31// ```
32// struct Baz;
33// fn baz() -> Baz { Baz }
34// fn foo() {
35// bar("", baz());
36// }
37//
38// fn bar(arg: &str, baz: Baz) ${0:-> ()} {
39// todo!()
40// }
41//
42// ```
43pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
44 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
45 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
46 let path = path_expr.path()?;
47
48 if ctx.sema.resolve_path(&path).is_some() {
49 // The function call already resolves, no need to add a function
50 return None;
51 }
52
53 let target_module = match path.qualifier() {
54 Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
55 Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => Some(module),
56 _ => return None,
57 },
58 None => None,
59 };
60
61 let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
62
63 let target = call.syntax().text_range();
64 acc.add(
65 AssistId("generate_function", AssistKind::Generate),
66 format!("Generate `{}` function", function_builder.fn_name),
67 target,
68 |builder| {
69 let function_template = function_builder.render();
70 builder.edit_file(function_template.file);
71 let new_fn = function_template.to_string(ctx.config.snippet_cap);
72 match ctx.config.snippet_cap {
73 Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
74 None => builder.insert(function_template.insert_offset, new_fn),
75 }
76 },
77 )
78}
79
80struct FunctionTemplate {
81 insert_offset: TextSize,
82 leading_ws: String,
83 fn_def: ast::Fn,
84 ret_type: ast::RetType,
85 trailing_ws: String,
86 file: FileId,
87}
88
89impl FunctionTemplate {
90 fn to_string(&self, cap: Option<SnippetCap>) -> String {
91 let f = match cap {
92 Some(cap) => {
93 render_snippet(cap, self.fn_def.syntax(), Cursor::Replace(self.ret_type.syntax()))
94 }
95 None => self.fn_def.to_string(),
96 };
97 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
98 }
99}
100
101struct FunctionBuilder {
102 target: GeneratedFunctionTarget,
103 fn_name: ast::Name,
104 type_params: Option<ast::GenericParamList>,
105 params: ast::ParamList,
106 file: FileId,
107 needs_pub: bool,
108}
109
110impl FunctionBuilder {
111 /// Prepares a generated function that matches `call`.
112 /// The function is generated in `target_module` or next to `call`
113 fn from_call(
114 ctx: &AssistContext,
115 call: &ast::CallExpr,
116 path: &ast::Path,
117 target_module: Option<hir::Module>,
118 ) -> Option<Self> {
119 let mut file = ctx.frange.file_id;
120 let target = match &target_module {
121 Some(target_module) => {
122 let module_source = target_module.definition_source(ctx.db());
123 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
124 file = in_file;
125 target
126 }
127 None => next_space_for_fn_after_call_site(&call)?,
128 };
129 let needs_pub = target_module.is_some();
130 let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?;
131 let fn_name = fn_name(&path)?;
132 let (type_params, params) = fn_args(ctx, target_module, &call)?;
133
134 Some(Self { target, fn_name, type_params, params, file, needs_pub })
135 }
136
137 fn render(self) -> FunctionTemplate {
138 let placeholder_expr = make::expr_todo();
139 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
140 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
141 let mut fn_def = make::fn_(
142 visibility,
143 self.fn_name,
144 self.type_params,
145 self.params,
146 fn_body,
147 Some(make::ret_type(make::ty_unit())),
148 );
149 let leading_ws;
150 let trailing_ws;
151
152 let insert_offset = match self.target {
153 GeneratedFunctionTarget::BehindItem(it) => {
154 let indent = IndentLevel::from_node(&it);
155 leading_ws = format!("\n\n{}", indent);
156 fn_def = fn_def.indent(indent);
157 trailing_ws = String::new();
158 it.text_range().end()
159 }
160 GeneratedFunctionTarget::InEmptyItemList(it) => {
161 let indent = IndentLevel::from_node(it.syntax());
162 leading_ws = format!("\n{}", indent + 1);
163 fn_def = fn_def.indent(indent + 1);
164 trailing_ws = format!("\n{}", indent);
165 it.syntax().text_range().start() + TextSize::of('{')
166 }
167 };
168
169 FunctionTemplate {
170 insert_offset,
171 leading_ws,
172 ret_type: fn_def.ret_type().unwrap(),
173 fn_def,
174 trailing_ws,
175 file: self.file,
176 }
177 }
178}
179
180enum GeneratedFunctionTarget {
181 BehindItem(SyntaxNode),
182 InEmptyItemList(ast::ItemList),
183}
184
185impl GeneratedFunctionTarget {
186 fn syntax(&self) -> &SyntaxNode {
187 match self {
188 GeneratedFunctionTarget::BehindItem(it) => it,
189 GeneratedFunctionTarget::InEmptyItemList(it) => it.syntax(),
190 }
191 }
192}
193
194fn fn_name(call: &ast::Path) -> Option<ast::Name> {
195 let name = call.segment()?.syntax().to_string();
196 Some(make::name(&name))
197}
198
199/// Computes the type variables and arguments required for the generated function
200fn fn_args(
201 ctx: &AssistContext,
202 target_module: hir::Module,
203 call: &ast::CallExpr,
204) -> Option<(Option<ast::GenericParamList>, ast::ParamList)> {
205 let mut arg_names = Vec::new();
206 let mut arg_types = Vec::new();
207 for arg in call.arg_list()?.args() {
208 arg_names.push(match fn_arg_name(&arg) {
209 Some(name) => name,
210 None => String::from("arg"),
211 });
212 arg_types.push(match fn_arg_type(ctx, target_module, &arg) {
213 Some(ty) => ty,
214 None => String::from("()"),
215 });
216 }
217 deduplicate_arg_names(&mut arg_names);
218 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| make::param(name, ty));
219 Some((None, make::param_list(params)))
220}
221
222/// Makes duplicate argument names unique by appending incrementing numbers.
223///
224/// ```
225/// let mut names: Vec<String> =
226/// vec!["foo".into(), "foo".into(), "bar".into(), "baz".into(), "bar".into()];
227/// deduplicate_arg_names(&mut names);
228/// let expected: Vec<String> =
229/// vec!["foo_1".into(), "foo_2".into(), "bar_1".into(), "baz".into(), "bar_2".into()];
230/// assert_eq!(names, expected);
231/// ```
232fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
233 let arg_name_counts = arg_names.iter().fold(FxHashMap::default(), |mut m, name| {
234 *m.entry(name).or_insert(0) += 1;
235 m
236 });
237 let duplicate_arg_names: FxHashSet<String> = arg_name_counts
238 .into_iter()
239 .filter(|(_, count)| *count >= 2)
240 .map(|(name, _)| name.clone())
241 .collect();
242
243 let mut counter_per_name = FxHashMap::default();
244 for arg_name in arg_names.iter_mut() {
245 if duplicate_arg_names.contains(arg_name) {
246 let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
247 arg_name.push('_');
248 arg_name.push_str(&counter.to_string());
249 *counter += 1;
250 }
251 }
252}
253
254fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
255 match fn_arg {
256 ast::Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
257 _ => Some(
258 fn_arg
259 .syntax()
260 .descendants()
261 .filter(|d| ast::NameRef::can_cast(d.kind()))
262 .last()?
263 .to_string(),
264 ),
265 }
266}
267
268fn fn_arg_type(
269 ctx: &AssistContext,
270 target_module: hir::Module,
271 fn_arg: &ast::Expr,
272) -> Option<String> {
273 let ty = ctx.sema.type_of_expr(fn_arg)?;
274 if ty.is_unknown() {
275 return None;
276 }
277
278 if let Ok(rendered) = ty.display_source_code(ctx.db(), target_module.into()) {
279 Some(rendered)
280 } else {
281 None
282 }
283}
284
285/// Returns the position inside the current mod or file
286/// directly after the current block
287/// We want to write the generated function directly after
288/// fns, impls or macro calls, but inside mods
289fn next_space_for_fn_after_call_site(expr: &ast::CallExpr) -> Option<GeneratedFunctionTarget> {
290 let mut ancestors = expr.syntax().ancestors().peekable();
291 let mut last_ancestor: Option<SyntaxNode> = None;
292 while let Some(next_ancestor) = ancestors.next() {
293 match next_ancestor.kind() {
294 SyntaxKind::SOURCE_FILE => {
295 break;
296 }
297 SyntaxKind::ITEM_LIST => {
298 if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) {
299 break;
300 }
301 }
302 _ => {}
303 }
304 last_ancestor = Some(next_ancestor);
305 }
306 last_ancestor.map(GeneratedFunctionTarget::BehindItem)
307}
308
309fn next_space_for_fn_in_module(
310 db: &dyn hir::db::AstDatabase,
311 module_source: &hir::InFile<hir::ModuleSource>,
312) -> Option<(FileId, GeneratedFunctionTarget)> {
313 let file = module_source.file_id.original_file(db);
314 let assist_item = match &module_source.value {
315 hir::ModuleSource::SourceFile(it) => {
316 if let Some(last_item) = it.items().last() {
317 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
318 } else {
319 GeneratedFunctionTarget::BehindItem(it.syntax().clone())
320 }
321 }
322 hir::ModuleSource::Module(it) => {
323 if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) {
324 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
325 } else {
326 GeneratedFunctionTarget::InEmptyItemList(it.item_list()?)
327 }
328 }
329 };
330 Some((file, assist_item))
331}
332
333#[cfg(test)]
334mod tests {
335 use crate::tests::{check_assist, check_assist_not_applicable};
336
337 use super::*;
338
339 #[test]
340 fn add_function_with_no_args() {
341 check_assist(
342 generate_function,
343 r"
344fn foo() {
345 bar$0();
346}
347",
348 r"
349fn foo() {
350 bar();
351}
352
353fn bar() ${0:-> ()} {
354 todo!()
355}
356",
357 )
358 }
359
360 #[test]
361 fn add_function_from_method() {
362 // This ensures that the function is correctly generated
363 // in the next outer mod or file
364 check_assist(
365 generate_function,
366 r"
367impl Foo {
368 fn foo() {
369 bar$0();
370 }
371}
372",
373 r"
374impl Foo {
375 fn foo() {
376 bar();
377 }
378}
379
380fn bar() ${0:-> ()} {
381 todo!()
382}
383",
384 )
385 }
386
387 #[test]
388 fn add_function_directly_after_current_block() {
389 // The new fn should not be created at the end of the file or module
390 check_assist(
391 generate_function,
392 r"
393fn foo1() {
394 bar$0();
395}
396
397fn foo2() {}
398",
399 r"
400fn foo1() {
401 bar();
402}
403
404fn bar() ${0:-> ()} {
405 todo!()
406}
407
408fn foo2() {}
409",
410 )
411 }
412
413 #[test]
414 fn add_function_with_no_args_in_same_module() {
415 check_assist(
416 generate_function,
417 r"
418mod baz {
419 fn foo() {
420 bar$0();
421 }
422}
423",
424 r"
425mod baz {
426 fn foo() {
427 bar();
428 }
429
430 fn bar() ${0:-> ()} {
431 todo!()
432 }
433}
434",
435 )
436 }
437
438 #[test]
439 fn add_function_with_function_call_arg() {
440 check_assist(
441 generate_function,
442 r"
443struct Baz;
444fn baz() -> Baz { todo!() }
445fn foo() {
446 bar$0(baz());
447}
448",
449 r"
450struct Baz;
451fn baz() -> Baz { todo!() }
452fn foo() {
453 bar(baz());
454}
455
456fn bar(baz: Baz) ${0:-> ()} {
457 todo!()
458}
459",
460 );
461 }
462
463 #[test]
464 fn add_function_with_method_call_arg() {
465 check_assist(
466 generate_function,
467 r"
468struct Baz;
469impl Baz {
470 fn foo(&self) -> Baz {
471 ba$0r(self.baz())
472 }
473 fn baz(&self) -> Baz {
474 Baz
475 }
476}
477",
478 r"
479struct Baz;
480impl Baz {
481 fn foo(&self) -> Baz {
482 bar(self.baz())
483 }
484 fn baz(&self) -> Baz {
485 Baz
486 }
487}
488
489fn bar(baz: Baz) ${0:-> ()} {
490 todo!()
491}
492",
493 )
494 }
495
496 #[test]
497 fn add_function_with_string_literal_arg() {
498 check_assist(
499 generate_function,
500 r#"
501fn foo() {
502 $0bar("bar")
503}
504"#,
505 r#"
506fn foo() {
507 bar("bar")
508}
509
510fn bar(arg: &str) ${0:-> ()} {
511 todo!()
512}
513"#,
514 )
515 }
516
517 #[test]
518 fn add_function_with_char_literal_arg() {
519 check_assist(
520 generate_function,
521 r#"
522fn foo() {
523 $0bar('x')
524}
525"#,
526 r#"
527fn foo() {
528 bar('x')
529}
530
531fn bar(arg: char) ${0:-> ()} {
532 todo!()
533}
534"#,
535 )
536 }
537
538 #[test]
539 fn add_function_with_int_literal_arg() {
540 check_assist(
541 generate_function,
542 r"
543fn foo() {
544 $0bar(42)
545}
546",
547 r"
548fn foo() {
549 bar(42)
550}
551
552fn bar(arg: i32) ${0:-> ()} {
553 todo!()
554}
555",
556 )
557 }
558
559 #[test]
560 fn add_function_with_cast_int_literal_arg() {
561 check_assist(
562 generate_function,
563 r"
564fn foo() {
565 $0bar(42 as u8)
566}
567",
568 r"
569fn foo() {
570 bar(42 as u8)
571}
572
573fn bar(arg: u8) ${0:-> ()} {
574 todo!()
575}
576",
577 )
578 }
579
580 #[test]
581 fn name_of_cast_variable_is_used() {
582 // Ensures that the name of the cast type isn't used
583 // in the generated function signature.
584 check_assist(
585 generate_function,
586 r"
587fn foo() {
588 let x = 42;
589 bar$0(x as u8)
590}
591",
592 r"
593fn foo() {
594 let x = 42;
595 bar(x as u8)
596}
597
598fn bar(x: u8) ${0:-> ()} {
599 todo!()
600}
601",
602 )
603 }
604
605 #[test]
606 fn add_function_with_variable_arg() {
607 check_assist(
608 generate_function,
609 r"
610fn foo() {
611 let worble = ();
612 $0bar(worble)
613}
614",
615 r"
616fn foo() {
617 let worble = ();
618 bar(worble)
619}
620
621fn bar(worble: ()) ${0:-> ()} {
622 todo!()
623}
624",
625 )
626 }
627
628 #[test]
629 fn add_function_with_impl_trait_arg() {
630 check_assist(
631 generate_function,
632 r"
633trait Foo {}
634fn foo() -> impl Foo {
635 todo!()
636}
637fn baz() {
638 $0bar(foo())
639}
640",
641 r"
642trait Foo {}
643fn foo() -> impl Foo {
644 todo!()
645}
646fn baz() {
647 bar(foo())
648}
649
650fn bar(foo: impl Foo) ${0:-> ()} {
651 todo!()
652}
653",
654 )
655 }
656
657 #[test]
658 fn borrowed_arg() {
659 check_assist(
660 generate_function,
661 r"
662struct Baz;
663fn baz() -> Baz { todo!() }
664
665fn foo() {
666 bar$0(&baz())
667}
668",
669 r"
670struct Baz;
671fn baz() -> Baz { todo!() }
672
673fn foo() {
674 bar(&baz())
675}
676
677fn bar(baz: &Baz) ${0:-> ()} {
678 todo!()
679}
680",
681 )
682 }
683
684 #[test]
685 fn add_function_with_qualified_path_arg() {
686 check_assist(
687 generate_function,
688 r"
689mod Baz {
690 pub struct Bof;
691 pub fn baz() -> Bof { Bof }
692}
693fn foo() {
694 $0bar(Baz::baz())
695}
696",
697 r"
698mod Baz {
699 pub struct Bof;
700 pub fn baz() -> Bof { Bof }
701}
702fn foo() {
703 bar(Baz::baz())
704}
705
706fn bar(baz: Baz::Bof) ${0:-> ()} {
707 todo!()
708}
709",
710 )
711 }
712
713 #[test]
714 #[ignore]
715 // FIXME fix printing the generics of a `Ty` to make this test pass
716 fn add_function_with_generic_arg() {
717 check_assist(
718 generate_function,
719 r"
720fn foo<T>(t: T) {
721 $0bar(t)
722}
723",
724 r"
725fn foo<T>(t: T) {
726 bar(t)
727}
728
729fn bar<T>(t: T) ${0:-> ()} {
730 todo!()
731}
732",
733 )
734 }
735
736 #[test]
737 #[ignore]
738 // FIXME Fix function type printing to make this test pass
739 fn add_function_with_fn_arg() {
740 check_assist(
741 generate_function,
742 r"
743struct Baz;
744impl Baz {
745 fn new() -> Self { Baz }
746}
747fn foo() {
748 $0bar(Baz::new);
749}
750",
751 r"
752struct Baz;
753impl Baz {
754 fn new() -> Self { Baz }
755}
756fn foo() {
757 bar(Baz::new);
758}
759
760fn bar(arg: fn() -> Baz) ${0:-> ()} {
761 todo!()
762}
763",
764 )
765 }
766
767 #[test]
768 #[ignore]
769 // FIXME Fix closure type printing to make this test pass
770 fn add_function_with_closure_arg() {
771 check_assist(
772 generate_function,
773 r"
774fn foo() {
775 let closure = |x: i64| x - 1;
776 $0bar(closure)
777}
778",
779 r"
780fn foo() {
781 let closure = |x: i64| x - 1;
782 bar(closure)
783}
784
785fn bar(closure: impl Fn(i64) -> i64) ${0:-> ()} {
786 todo!()
787}
788",
789 )
790 }
791
792 #[test]
793 fn unresolveable_types_default_to_unit() {
794 check_assist(
795 generate_function,
796 r"
797fn foo() {
798 $0bar(baz)
799}
800",
801 r"
802fn foo() {
803 bar(baz)
804}
805
806fn bar(baz: ()) ${0:-> ()} {
807 todo!()
808}
809",
810 )
811 }
812
813 #[test]
814 fn arg_names_dont_overlap() {
815 check_assist(
816 generate_function,
817 r"
818struct Baz;
819fn baz() -> Baz { Baz }
820fn foo() {
821 $0bar(baz(), baz())
822}
823",
824 r"
825struct Baz;
826fn baz() -> Baz { Baz }
827fn foo() {
828 bar(baz(), baz())
829}
830
831fn bar(baz_1: Baz, baz_2: Baz) ${0:-> ()} {
832 todo!()
833}
834",
835 )
836 }
837
838 #[test]
839 fn arg_name_counters_start_at_1_per_name() {
840 check_assist(
841 generate_function,
842 r#"
843struct Baz;
844fn baz() -> Baz { Baz }
845fn foo() {
846 $0bar(baz(), baz(), "foo", "bar")
847}
848"#,
849 r#"
850struct Baz;
851fn baz() -> Baz { Baz }
852fn foo() {
853 bar(baz(), baz(), "foo", "bar")
854}
855
856fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) ${0:-> ()} {
857 todo!()
858}
859"#,
860 )
861 }
862
863 #[test]
864 fn add_function_in_module() {
865 check_assist(
866 generate_function,
867 r"
868mod bar {}
869
870fn foo() {
871 bar::my_fn$0()
872}
873",
874 r"
875mod bar {
876 pub(crate) fn my_fn() ${0:-> ()} {
877 todo!()
878 }
879}
880
881fn foo() {
882 bar::my_fn()
883}
884",
885 )
886 }
887
888 #[test]
889 #[ignore]
890 // Ignored until local imports are supported.
891 // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
892 fn qualified_path_uses_correct_scope() {
893 check_assist(
894 generate_function,
895 "
896mod foo {
897 pub struct Foo;
898}
899fn bar() {
900 use foo::Foo;
901 let foo = Foo;
902 baz$0(foo)
903}
904",
905 "
906mod foo {
907 pub struct Foo;
908}
909fn bar() {
910 use foo::Foo;
911 let foo = Foo;
912 baz(foo)
913}
914
915fn baz(foo: foo::Foo) ${0:-> ()} {
916 todo!()
917}
918",
919 )
920 }
921
922 #[test]
923 fn add_function_in_module_containing_other_items() {
924 check_assist(
925 generate_function,
926 r"
927mod bar {
928 fn something_else() {}
929}
930
931fn foo() {
932 bar::my_fn$0()
933}
934",
935 r"
936mod bar {
937 fn something_else() {}
938
939 pub(crate) fn my_fn() ${0:-> ()} {
940 todo!()
941 }
942}
943
944fn foo() {
945 bar::my_fn()
946}
947",
948 )
949 }
950
951 #[test]
952 fn add_function_in_nested_module() {
953 check_assist(
954 generate_function,
955 r"
956mod bar {
957 mod baz {}
958}
959
960fn foo() {
961 bar::baz::my_fn$0()
962}
963",
964 r"
965mod bar {
966 mod baz {
967 pub(crate) fn my_fn() ${0:-> ()} {
968 todo!()
969 }
970 }
971}
972
973fn foo() {
974 bar::baz::my_fn()
975}
976",
977 )
978 }
979
980 #[test]
981 fn add_function_in_another_file() {
982 check_assist(
983 generate_function,
984 r"
985//- /main.rs
986mod foo;
987
988fn main() {
989 foo::bar$0()
990}
991//- /foo.rs
992",
993 r"
994
995
996pub(crate) fn bar() ${0:-> ()} {
997 todo!()
998}",
999 )
1000 }
1001
1002 #[test]
1003 fn add_function_not_applicable_if_function_already_exists() {
1004 check_assist_not_applicable(
1005 generate_function,
1006 r"
1007fn foo() {
1008 bar$0();
1009}
1010
1011fn bar() {}
1012",
1013 )
1014 }
1015
1016 #[test]
1017 fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
1018 check_assist_not_applicable(
1019 // bar is resolved, but baz isn't.
1020 // The assist is only active if the cursor is on an unresolved path,
1021 // but the assist should only be offered if the path is a function call.
1022 generate_function,
1023 r"
1024fn foo() {
1025 bar(b$0az);
1026}
1027
1028fn bar(baz: ()) {}
1029",
1030 )
1031 }
1032
1033 #[test]
1034 #[ignore]
1035 fn create_method_with_no_args() {
1036 check_assist(
1037 generate_function,
1038 r"
1039struct Foo;
1040impl Foo {
1041 fn foo(&self) {
1042 self.bar()$0;
1043 }
1044}
1045 ",
1046 r"
1047struct Foo;
1048impl Foo {
1049 fn foo(&self) {
1050 self.bar();
1051 }
1052 fn bar(&self) {
1053 todo!();
1054 }
1055}
1056 ",
1057 )
1058 }
1059}