1use hir::{
2 Adt, AsAssocItem, HasSource, HirDisplay, Module, PathResolution, Semantics, StructKind, Type,
3 TypeInfo,
4};
5use ide_db::{
6 FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap,
7 defs::{Definition, NameRefClass},
8 famous_defs::FamousDefs,
9 helpers::is_editable_crate,
10 path_transform::PathTransform,
11 source_change::SourceChangeBuilder,
12};
13use itertools::Itertools;
14use stdx::to_lower_snake_case;
15use syntax::{
16 Edition, SyntaxKind, SyntaxNode, T, TextRange,
17 ast::{
18 self, AstNode, BlockExpr, CallExpr, HasArgList, HasGenericParams, HasModuleItem,
19 HasTypeBounds,
20 edit::{AstNodeEdit, IndentLevel},
21 syntax_factory::SyntaxFactory,
22 },
23 syntax_editor::{Position, SyntaxEditor},
24};
25
26use crate::{
27 AssistContext, AssistId, Assists,
28 utils::{convert_reference_type, expr_fill_default, find_struct_impl},
29};
30
31pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
57 gen_fn(acc, ctx).or_else(|| gen_method(acc, ctx))
58}
59
60fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
61 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
62 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
63 let path = path_expr.path()?;
64 let name_ref = path.segment()?.name_ref()?;
65 if ctx.sema.resolve_path(&path).is_some() {
66 return None;
68 }
69
70 let fn_name = &*name_ref.text();
71 let TargetInfo { target_module, adt_info, target, file } =
72 fn_target_info(ctx, path, &call, fn_name)?;
73
74 if let Some(m) = target_module
75 && !is_editable_crate(m.krate(ctx.db()), ctx.db())
76 {
77 return None;
78 }
79 let make = SyntaxFactory::without_mappings();
80
81 let function_builder =
82 FunctionBuilder::from_call(&make, ctx, &call, fn_name, target_module, target, &adt_info)?;
83 let text_range = call.syntax().text_range();
84 let label = format!("Generate {} function", function_builder.fn_name);
85 add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_info, label)
86}
87
88struct TargetInfo {
89 target_module: Option<Module>,
90 adt_info: Option<AdtInfo>,
91 target: GeneratedFunctionTarget,
92 file: FileId,
93}
94
95impl TargetInfo {
96 fn new(
97 target_module: Option<Module>,
98 adt_info: Option<AdtInfo>,
99 target: GeneratedFunctionTarget,
100 file: FileId,
101 ) -> Self {
102 Self { target_module, adt_info, target, file }
103 }
104}
105
106fn fn_target_info(
107 ctx: &AssistContext<'_, '_>,
108 path: ast::Path,
109 call: &CallExpr,
110 fn_name: &str,
111) -> Option<TargetInfo> {
112 match path.qualifier() {
113 Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
114 Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
115 get_fn_target_info(ctx, Some(module), call.clone())
116 }
117 Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
118 if let hir::Adt::Enum(_) = adt {
119 if fn_name.starts_with(char::is_uppercase) {
121 return None;
122 }
123 }
124
125 assoc_fn_target_info(ctx, call, adt, fn_name)
126 }
127 Some(hir::PathResolution::SelfType(impl_)) => {
128 let adt = impl_.self_ty(ctx.db()).as_adt()?;
129 assoc_fn_target_info(ctx, call, adt, fn_name)
130 }
131 _ => None,
132 },
133 _ => get_fn_target_info(ctx, None, call.clone()),
134 }
135}
136
137fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
138 let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
139 if ctx.sema.resolve_method_call(&call).is_some() {
140 return None;
141 }
142
143 let fn_name = call.name_ref()?;
144 let receiver_ty = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references();
145 let adt = receiver_ty.as_adt()?;
146
147 let target_module = adt.module(ctx.sema.db);
148 if !is_editable_crate(target_module.krate(ctx.db()), ctx.db()) {
149 return None;
150 }
151
152 let enclosing_impl = ctx.find_node_at_offset::<ast::Impl>();
153 let cursor_impl = enclosing_impl.filter(|impl_| {
154 ctx.sema.to_def(impl_).is_some_and(|def| {
155 def.self_ty(ctx.sema.db).as_adt() == Some(adt) && def.trait_(ctx.sema.db).is_none()
156 })
157 });
158
159 let (impl_, file) = if let Some(impl_) = cursor_impl {
160 (Some(impl_), ctx.vfs_file_id())
161 } else {
162 get_adt_source(ctx, &adt, fn_name.text().as_str())?
163 };
164 let target = get_method_target(ctx, &impl_, &adt)?;
165
166 let make = SyntaxFactory::without_mappings();
167
168 let function_builder = FunctionBuilder::from_method_call(
169 &make,
170 ctx,
171 &call,
172 &fn_name,
173 receiver_ty,
174 target_module,
175 target,
176 )?;
177 let text_range = call.syntax().text_range();
178 let adt_info = AdtInfo::new(adt, impl_.is_some());
179 let label = format!("Generate {} method", function_builder.fn_name);
180 add_func_to_accumulator(acc, ctx, text_range, function_builder, file, Some(adt_info), label)
181}
182
183fn add_func_to_accumulator(
184 acc: &mut Assists,
185 ctx: &AssistContext<'_, '_>,
186 text_range: TextRange,
187 function_builder: FunctionBuilder,
188 file: FileId,
189 adt_info: Option<AdtInfo>,
190 label: String,
191) -> Option<()> {
192 acc.add(AssistId::generate("generate_function"), label, text_range, |edit| {
193 let target = function_builder.target.clone();
194 let snippet_cap = ctx.config.snippet_cap;
195
196 if let Some(adt) = adt_info
197 .and_then(|adt_info| if adt_info.impl_exists { None } else { Some(adt_info.adt) })
198 {
199 target.insert_impl_at(edit, file, ctx, &function_builder, adt, snippet_cap);
200 } else {
201 target.insert_fn_at(edit, file, &function_builder, snippet_cap);
202 }
203 })
204}
205
206fn get_adt_source(
207 ctx: &AssistContext<'_, '_>,
208 adt: &hir::Adt,
209 fn_name: &str,
210) -> Option<(Option<ast::Impl>, FileId)> {
211 let range = adt.source(ctx.sema.db)?.syntax().original_file_range_rooted(ctx.sema.db);
212
213 let file = ctx.sema.parse(range.file_id);
214 let adt_source =
215 ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
216 find_struct_impl(ctx, &adt_source, &[fn_name.to_owned()])
217 .map(|impl_| (impl_, range.file_id.file_id(ctx.db())))
218}
219
220struct FunctionBuilder {
221 target: GeneratedFunctionTarget,
222 fn_name: ast::Name,
223 generic_param_list: Option<ast::GenericParamList>,
224 where_clause: Option<ast::WhereClause>,
225 params: ast::ParamList,
226 fn_body: BlockExpr,
227 ret_type: Option<ast::RetType>,
228 should_focus_return_type: bool,
229 visibility: Visibility,
230 is_async: bool,
231 target_edition: Edition,
232}
233
234impl FunctionBuilder {
235 fn from_call(
238 make: &SyntaxFactory,
239 ctx: &AssistContext<'_, '_>,
240 call: &ast::CallExpr,
241 fn_name: &str,
242 target_module: Option<Module>,
243 target: GeneratedFunctionTarget,
244 adt_info: &Option<AdtInfo>,
245 ) -> Option<Self> {
246 let target_module =
247 target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
248 let target_edition = target_module.krate(ctx.db()).edition(ctx.db());
249
250 let current_module = ctx.sema.scope(call.syntax())?.module();
251 let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
252 let fn_name = make.name(fn_name);
253 let mut necessary_generic_params = FxHashSet::default();
254 let params = fn_args(
255 make,
256 ctx,
257 target_module,
258 ast::CallableExpr::Call(call.clone()),
259 &mut necessary_generic_params,
260 )?;
261
262 let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
263 let is_async = await_expr.is_some();
264
265 let ret_type;
266 let should_focus_return_type;
267 let fn_body;
268
269 if let Some(body) =
272 make_fn_body_as_new_function(make, ctx, &fn_name.text(), adt_info, target_edition)
273 {
274 ret_type = Some(make.ret_type(make.ty_path(make.ident_path("Self")).into()));
275 should_focus_return_type = false;
276 fn_body = body;
277 } else {
278 let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
279 (ret_type, should_focus_return_type) = make_return_type(
280 make,
281 ctx,
282 &expr_for_ret_ty,
283 target_module,
284 &mut necessary_generic_params,
285 );
286 let placeholder_expr = expr_fill_default(ctx.config);
287 fn_body = make.block_expr(vec![], Some(placeholder_expr));
288 };
289
290 let (generic_param_list, where_clause) =
291 fn_generic_params(make, ctx, necessary_generic_params, &target)?;
292
293 Some(Self {
294 target,
295 fn_name,
296 generic_param_list,
297 where_clause,
298 params,
299 fn_body,
300 ret_type,
301 should_focus_return_type,
302 visibility,
303 is_async,
304 target_edition,
305 })
306 }
307
308 fn from_method_call(
309 make: &SyntaxFactory,
310 ctx: &AssistContext<'_, '_>,
311 call: &ast::MethodCallExpr,
312 name: &ast::NameRef,
313 receiver_ty: Type<'_>,
314 target_module: Module,
315 target: GeneratedFunctionTarget,
316 ) -> Option<Self> {
317 let target_edition = target_module.krate(ctx.db()).edition(ctx.db());
318
319 let current_module = ctx.sema.scope(call.syntax())?.module();
320 let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
321
322 let fn_name = make.name(name.ident_token()?.text());
323 let mut necessary_generic_params = FxHashSet::default();
324 necessary_generic_params.extend(receiver_ty.generic_params(ctx.db()));
325 let params = fn_args(
326 make,
327 ctx,
328 target_module,
329 ast::CallableExpr::MethodCall(call.clone()),
330 &mut necessary_generic_params,
331 )?;
332
333 let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
334 let is_async = await_expr.is_some();
335
336 let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
337 let (ret_type, should_focus_return_type) = make_return_type(
338 make,
339 ctx,
340 &expr_for_ret_ty,
341 target_module,
342 &mut necessary_generic_params,
343 );
344
345 let (generic_param_list, where_clause) =
346 fn_generic_params(make, ctx, necessary_generic_params, &target)?;
347
348 let placeholder_expr = expr_fill_default(ctx.config);
349 let fn_body = make.block_expr(vec![], Some(placeholder_expr));
350
351 Some(Self {
352 target,
353 fn_name,
354 generic_param_list,
355 where_clause,
356 params,
357 fn_body,
358 ret_type,
359 should_focus_return_type,
360 visibility,
361 is_async,
362 target_edition,
363 })
364 }
365
366 fn render(&self, make: &SyntaxFactory) -> ast::Fn {
367 let visibility = match self.visibility {
368 Visibility::None => None,
369 Visibility::Crate => Some(make.visibility_pub_crate()),
370 Visibility::Pub => Some(make.visibility_pub()),
371 };
372 let type_params =
373 self.generic_param_list.clone().filter(|list| list.generic_params().next().is_some());
374 make.fn_(
375 None,
376 visibility,
377 self.fn_name.clone(),
378 type_params,
379 self.where_clause.clone(),
380 self.params.clone(),
381 self.fn_body.clone(),
382 self.ret_type.clone(),
383 self.is_async,
384 false, false,
386 false,
387 )
388 }
389}
390
391fn make_return_type(
401 make: &SyntaxFactory,
402 ctx: &AssistContext<'_, '_>,
403 expr: &ast::Expr,
404 target_module: Module,
405 necessary_generic_params: &mut FxHashSet<hir::GenericParam>,
406) -> (Option<ast::RetType>, bool) {
407 let (ret_ty, should_focus_return_type) =
408 match ctx.sema.type_of_expr(expr).map(TypeInfo::original) {
409 Some(ty) if ty.is_unknown() => (Some(make.ty_placeholder()), true),
410 None => (Some(make.ty_placeholder()), true),
411 Some(ty) if ty.is_unit() => (None, false),
412 Some(ty) => {
413 necessary_generic_params.extend(ty.generic_params(ctx.db()));
414 let rendered = ty.display_source_code(ctx.db(), target_module.into(), true);
415 match rendered {
416 Ok(rendered) => (Some(make.ty(&rendered)), false),
417 Err(_) => (Some(make.ty_placeholder()), true),
418 }
419 }
420 };
421 let ret_type = ret_ty.map(|ty| make.ret_type(ty));
422 (ret_type, should_focus_return_type)
423}
424
425fn make_fn_body_as_new_function(
426 make: &SyntaxFactory,
427 ctx: &AssistContext<'_, '_>,
428 fn_name: &str,
429 adt_info: &Option<AdtInfo>,
430 edition: Edition,
431) -> Option<ast::BlockExpr> {
432 if fn_name != "new" {
433 return None;
434 };
435 let adt_info = adt_info.as_ref()?;
436
437 let path_self = make.ident_path("Self");
438 let placeholder_expr = expr_fill_default(ctx.config);
439 let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() {
440 match strukt.kind(ctx.db()) {
441 StructKind::Record => {
442 let fields = strukt
443 .fields(ctx.db())
444 .iter()
445 .map(|field| {
446 make.record_expr_field(
447 make.name_ref(&format!(
448 "{}",
449 field.name(ctx.db()).display(ctx.db(), edition)
450 )),
451 Some(placeholder_expr.clone()),
452 )
453 })
454 .collect::<Vec<_>>();
455
456 make.record_expr(path_self, make.record_expr_field_list(fields)).into()
457 }
458 StructKind::Tuple => {
459 let args = strukt
460 .fields(ctx.db())
461 .iter()
462 .map(|_| placeholder_expr.clone())
463 .collect::<Vec<_>>();
464
465 make.expr_call(make.expr_path(path_self), make.arg_list(args)).into()
466 }
467 StructKind::Unit => make.expr_path(path_self),
468 }
469 } else {
470 placeholder_expr
471 };
472
473 let fn_body = make.block_expr(vec![], Some(tail_expr));
474 Some(fn_body)
475}
476
477fn get_fn_target_info(
478 ctx: &AssistContext<'_, '_>,
479 target_module: Option<Module>,
480 call: CallExpr,
481) -> Option<TargetInfo> {
482 let (target, file) = get_fn_target(ctx, target_module, call)?;
483 Some(TargetInfo::new(target_module, None, target, file))
484}
485
486fn get_fn_target(
487 ctx: &AssistContext<'_, '_>,
488 target_module: Option<Module>,
489 call: CallExpr,
490) -> Option<(GeneratedFunctionTarget, FileId)> {
491 let mut file = ctx.vfs_file_id();
492 let target = match target_module {
493 Some(target_module) => {
494 let (in_file, target) = next_space_for_fn_in_module(ctx.db(), target_module);
495 file = in_file;
496 target
497 }
498 None => next_space_for_fn_after_call_site(ast::CallableExpr::Call(call))?,
499 };
500 Some((target, file))
501}
502
503fn get_method_target(
504 ctx: &AssistContext<'_, '_>,
505 impl_: &Option<ast::Impl>,
506 adt: &Adt,
507) -> Option<GeneratedFunctionTarget> {
508 let target = match impl_ {
509 Some(impl_) => GeneratedFunctionTarget::InImpl(impl_.clone()),
510 None => GeneratedFunctionTarget::AfterItem(adt.source(ctx.sema.db)?.syntax().value.clone()),
511 };
512 Some(target)
513}
514
515fn assoc_fn_target_info(
516 ctx: &AssistContext<'_, '_>,
517 call: &CallExpr,
518 adt: hir::Adt,
519 fn_name: &str,
520) -> Option<TargetInfo> {
521 let current_module = ctx.sema.scope(call.syntax())?.module();
522 let module = adt.module(ctx.sema.db);
523 let target_module = if current_module == module { None } else { Some(module) };
524 if current_module.krate(ctx.db()) != module.krate(ctx.db()) {
525 return None;
526 }
527 let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
528 let target = get_method_target(ctx, &impl_, &adt)?;
529 let adt_info = AdtInfo::new(adt, impl_.is_some());
530 Some(TargetInfo::new(target_module, Some(adt_info), target, file))
531}
532
533#[derive(Clone)]
534enum GeneratedFunctionTarget {
535 AfterItem(SyntaxNode),
536 InEmptyItemList(SyntaxNode),
537 InImpl(ast::Impl),
538}
539
540impl GeneratedFunctionTarget {
541 fn syntax(&self) -> &SyntaxNode {
542 match self {
543 GeneratedFunctionTarget::AfterItem(it) => it,
544 GeneratedFunctionTarget::InEmptyItemList(it) => it,
545 GeneratedFunctionTarget::InImpl(it) => it.syntax(),
546 }
547 }
548
549 fn parent(&self) -> SyntaxNode {
550 match self {
551 GeneratedFunctionTarget::AfterItem(it) => it.parent().expect("item without parent"),
552 GeneratedFunctionTarget::InEmptyItemList(it) => it.clone(),
553 GeneratedFunctionTarget::InImpl(it) => it.syntax().clone(),
554 }
555 }
556
557 fn insert_impl_at(
558 &self,
559 edit: &mut SourceChangeBuilder,
560 file: FileId,
561 ctx: &AssistContext<'_, '_>,
562 function_builder: &FunctionBuilder,
563 adt: Adt,
564 cap: Option<SnippetCap>,
565 ) {
566 let editor = edit.make_editor(self.syntax());
567
568 match self {
569 GeneratedFunctionTarget::AfterItem(item) => {
570 let position = if item.parent().is_some() {
571 Position::after(item)
572 } else {
573 Position::first_child_of(item)
574 };
575
576 let indent = IndentLevel::from_node(item);
577 insert_rendered_impl(
578 &editor,
579 edit,
580 ctx,
581 function_builder,
582 adt,
583 position,
584 indent,
585 indent,
586 cap,
587 );
588 }
589 GeneratedFunctionTarget::InEmptyItemList(item_list) => {
590 let insert_after =
591 item_list.children_with_tokens().find_or_first(|child| child.kind() == T!['{']);
592 let position = match insert_after {
593 Some(child) => Position::after(child),
594 None => Position::first_child_of(item_list),
595 };
596
597 let indent = IndentLevel::from_node(item_list);
598 let leading_indent = indent + 1;
599 insert_rendered_impl(
600 &editor,
601 edit,
602 ctx,
603 function_builder,
604 adt,
605 position,
606 indent,
607 leading_indent,
608 cap,
609 );
610 }
611 GeneratedFunctionTarget::InImpl(_) => {
612 unreachable!("can't insert an impl inside an impl")
613 }
614 }
615 edit.add_file_edits(file, editor);
616 }
617
618 fn insert_fn_at(
619 &self,
620 edit: &mut SourceChangeBuilder,
621 file: FileId,
622 function_builder: &FunctionBuilder,
623 cap: Option<SnippetCap>,
624 ) {
625 let editor = edit.make_editor(self.syntax());
626 let make = editor.make();
627
628 match self {
629 GeneratedFunctionTarget::AfterItem(item) => {
630 let position = if item.parent().is_some() {
631 Position::after(item)
632 } else {
633 Position::first_child_of(item)
634 };
635
636 let indent = IndentLevel::from_node(item);
637 insert_rendered_fn(
638 &editor,
639 edit,
640 function_builder,
641 position,
642 indent,
643 format!("\n\n{indent}"),
644 None,
645 cap,
646 );
647 }
648 GeneratedFunctionTarget::InEmptyItemList(item_list) => {
649 let insert_after =
650 item_list.children_with_tokens().find_or_first(|child| child.kind() == T!['{']);
651 let position = match insert_after {
652 Some(child) => Position::after(child),
653 None => Position::first_child_of(item_list),
654 };
655
656 let indent = IndentLevel::from_node(item_list);
657 let leading_indent = indent + 1;
658 insert_rendered_fn(
659 &editor,
660 edit,
661 function_builder,
662 position,
663 leading_indent,
664 format!("\n{leading_indent}"),
665 Some(format!("\n{indent}")),
666 cap,
667 );
668 }
669 GeneratedFunctionTarget::InImpl(impl_) => {
670 let leading_indent = impl_.indent_level() + 1;
671
672 if let Some(item_list) = impl_.assoc_item_list() {
673 let insert_after_item = item_list.assoc_items().last();
674 let insert_after = item_list
675 .assoc_items()
676 .last()
677 .map(|it| it.syntax().clone().into())
678 .or_else(|| {
679 item_list
680 .syntax()
681 .children_with_tokens()
682 .find_or_first(|child| child.kind() == T!['{'])
683 });
684 let position = match insert_after {
685 Some(child) => Position::after(child),
686 None => Position::first_child_of(item_list.syntax()),
687 };
688 let indent = impl_.indent_level();
689 let leading_ws = if insert_after_item.is_some() {
690 format!("\n\n{leading_indent}")
691 } else {
692 format!("\n{leading_indent}")
693 };
694 let trailing_ws = insert_after_item.is_none().then(|| format!("\n{indent}"));
695 insert_rendered_fn(
696 &editor,
697 edit,
698 function_builder,
699 position,
700 leading_indent,
701 leading_ws,
702 trailing_ws,
703 cap,
704 );
705 } else {
706 let func = function_builder.render(make).indent(leading_indent);
707 let item_list = make.assoc_item_list([func.into()]);
708 if let Some(fn_) = item_list.syntax().descendants().find_map(ast::Fn::cast) {
709 add_generated_fn_annotation(&editor, edit, function_builder, &fn_, cap);
710 }
711 editor.insert(Position::last_child_of(impl_.syntax()), item_list.syntax());
712 }
713 }
714 }
715 edit.add_file_edits(file, editor);
716 }
717}
718
719fn insert_rendered_impl(
720 editor: &SyntaxEditor,
721 edit: &mut SourceChangeBuilder,
722 ctx: &AssistContext<'_, '_>,
723 function_builder: &FunctionBuilder,
724 adt: Adt,
725 position: Position,
726 impl_indent: IndentLevel,
727 leading_ws_indent: IndentLevel,
728 cap: Option<SnippetCap>,
729) {
730 let make = editor.make();
731 let leading_ws = make.whitespace(&format!("\n{leading_ws_indent}"));
732 let name = make.ty_path(make.ident_path(&format!(
733 "{}",
734 adt.name(ctx.db()).display(ctx.db(), function_builder.target_edition)
735 )));
736
737 let fn_ = function_builder.render(make).indent(IndentLevel(1));
739 let impl_ =
740 make.impl_(None, None, None, name.into(), None, Some(make.assoc_item_list([fn_.into()])));
741 let impl_ = impl_.indent(impl_indent);
742 if let Some(fn_) = impl_.syntax().descendants().find_map(ast::Fn::cast) {
743 add_generated_fn_annotation(editor, edit, function_builder, &fn_, cap);
744 }
745
746 editor.insert_all(position, vec![leading_ws.into(), impl_.syntax().clone().into()]);
747}
748
749fn insert_rendered_fn(
750 editor: &SyntaxEditor,
751 edit: &mut SourceChangeBuilder,
752 function_builder: &FunctionBuilder,
753 position: Position,
754 indent: IndentLevel,
755 leading_ws: String,
756 trailing_ws: Option<String>,
757 cap: Option<SnippetCap>,
758) {
759 let make = editor.make();
760 let leading_ws = make.whitespace(&leading_ws);
761 let func = function_builder.render(make).indent(indent);
762 add_generated_fn_annotation(editor, edit, function_builder, &func, cap);
763
764 let mut elements = vec![leading_ws.into(), func.syntax().clone().into()];
765 if let Some(trailing_ws) = trailing_ws {
766 elements.push(make.whitespace(&trailing_ws).into());
767 }
768 editor.insert_all(position, elements);
769}
770
771fn add_generated_fn_annotation(
772 editor: &SyntaxEditor,
773 edit: &mut SourceChangeBuilder,
774 function_builder: &FunctionBuilder,
775 fn_: &ast::Fn,
776 cap: Option<SnippetCap>,
777) {
778 let Some(cap) = cap else { return };
779
780 let annotation = edit.make_placeholder_snippet(cap);
781 if function_builder.should_focus_return_type
782 && let Some(ret_type) = fn_.ret_type()
783 {
784 editor.add_annotation(ret_type.syntax(), annotation);
785 } else if let Some(tail_expr) = fn_.body().and_then(|body| body.tail_expr()) {
786 editor.add_annotation(tail_expr.syntax(), annotation);
787 }
788}
789
790struct AdtInfo {
791 adt: hir::Adt,
792 impl_exists: bool,
793}
794
795impl AdtInfo {
796 fn new(adt: Adt, impl_exists: bool) -> Self {
797 Self { adt, impl_exists }
798 }
799}
800
801fn fn_args(
803 make: &SyntaxFactory,
804 ctx: &AssistContext<'_, '_>,
805 target_module: Module,
806 call: ast::CallableExpr,
807 necessary_generic_params: &mut FxHashSet<hir::GenericParam>,
808) -> Option<ast::ParamList> {
809 let mut arg_names = Vec::new();
810 let mut arg_types = Vec::new();
811 for arg in call.arg_list()?.args() {
812 arg_names.push(fn_arg_name(&ctx.sema, &arg));
813 arg_types.push(fn_arg_type(ctx, target_module, &arg, necessary_generic_params));
814 }
815 deduplicate_arg_names(&mut arg_names);
816 let params = arg_names
817 .into_iter()
818 .zip(arg_types)
819 .map(|(name, ty)| make.param(make.simple_ident_pat(make.name(&name)).into(), make.ty(&ty)));
820
821 Some(make.param_list(
822 match call {
823 ast::CallableExpr::Call(_) => None,
824 ast::CallableExpr::MethodCall(_) => Some(make.self_param()),
825 },
826 params,
827 ))
828}
829
830fn fn_generic_params(
839 make: &SyntaxFactory,
840 ctx: &AssistContext<'_, '_>,
841 necessary_params: FxHashSet<hir::GenericParam>,
842 target: &GeneratedFunctionTarget,
843) -> Option<(Option<ast::GenericParamList>, Option<ast::WhereClause>)> {
844 if necessary_params.is_empty() {
845 return Some((None, None));
847 }
848
849 let (generic_params, where_preds) = params_and_where_preds_in_scope(ctx);
851
852 let mut generic_params = generic_params
854 .into_iter()
855 .filter_map(|it| compute_contained_params_in_generic_param(ctx, it))
856 .collect();
857 let mut where_preds = where_preds
858 .into_iter()
859 .filter_map(|it| compute_contained_params_in_where_pred(ctx, it))
860 .collect();
861
862 filter_unnecessary_bounds(&mut generic_params, &mut where_preds, necessary_params);
864 filter_bounds_in_scope(&mut generic_params, &mut where_preds, ctx, target);
865
866 let source_scope = generic_params.first().and_then(|param| ctx.sema.scope(param.node.syntax()));
867 let target_scope = source_scope.as_ref().and_then(|_| ctx.sema.scope(&target.parent()));
868
869 let generic_params: Vec<ast::GenericParam> =
870 generic_params.into_iter().map(|it| it.node).collect();
871 let where_preds: Vec<ast::WherePred> = where_preds.into_iter().map(|it| it.node).collect();
872
873 let (generic_params, where_preds) = if let Some(source_scope) = source_scope
874 && let Some(target_scope) = target_scope
875 && source_scope.module() != target_scope.module()
876 {
877 let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
879 let generic_params = generic_params.iter().map(|it| it.syntax());
880 let where_preds = where_preds.iter().map(|it| it.syntax());
881 transform
882 .apply_all(generic_params.chain(where_preds))
883 .into_iter()
884 .filter_map(|it| {
885 if let Some(it) = ast::GenericParam::cast(it.clone()) {
886 Some(either::Either::Left(it))
887 } else {
888 ast::WherePred::cast(it).map(either::Either::Right)
889 }
890 })
891 .partition_map(|it| it)
892 } else {
893 (generic_params, where_preds)
894 };
895
896 let generic_param_list = make.generic_param_list(generic_params);
897 let where_clause =
898 if where_preds.is_empty() { None } else { Some(make.where_clause(where_preds)) };
899
900 Some((Some(generic_param_list), where_clause))
901}
902
903fn params_and_where_preds_in_scope(
904 ctx: &AssistContext<'_, '_>,
905) -> (Vec<ast::GenericParam>, Vec<ast::WherePred>) {
906 let Some(body) = containing_body(ctx) else {
907 return Default::default();
908 };
909
910 let mut generic_params = Vec::new();
911 let mut where_clauses = Vec::new();
912
913 let db = ctx.db();
919 if let Some(parent) = body.as_assoc_item(db).map(|it| it.container(db)) {
920 match parent {
921 hir::AssocItemContainer::Impl(it) => {
922 let (params, clauses) = get_bounds_in_scope(ctx, it);
923 generic_params.extend(params);
924 where_clauses.extend(clauses);
925 }
926 hir::AssocItemContainer::Trait(it) => {
927 let (params, clauses) = get_bounds_in_scope(ctx, it);
928 generic_params.extend(params);
929 where_clauses.extend(clauses);
930 }
931 }
932 }
933
934 if let hir::DefWithBody::Function(it) = body {
937 let (params, clauses) = get_bounds_in_scope(ctx, it);
938 generic_params.extend(params);
939 where_clauses.extend(clauses);
940 }
941
942 (generic_params, where_clauses)
943}
944
945fn containing_body(ctx: &AssistContext<'_, '_>) -> Option<hir::DefWithBody> {
946 let item: ast::Item = ctx.find_node_at_offset()?;
947 let def = match item {
948 ast::Item::Fn(it) => ctx.sema.to_def(&it)?.into(),
949 ast::Item::Const(it) => ctx.sema.to_def(&it)?.into(),
950 ast::Item::Static(it) => ctx.sema.to_def(&it)?.into(),
951 _ => return None,
952 };
953 Some(def)
954}
955
956fn get_bounds_in_scope<D>(
957 ctx: &AssistContext<'_, '_>,
958 def: D,
959) -> (impl Iterator<Item = ast::GenericParam>, impl Iterator<Item = ast::WherePred>)
960where
961 D: HasSource,
962 D::Ast: HasGenericParams,
963{
964 let node = ctx.sema.source(def).expect("definition's source couldn't be found").value;
967 let generic_params = node.generic_param_list().into_iter().flat_map(|it| it.generic_params());
968 let where_clauses = node.where_clause().into_iter().flat_map(|it| it.predicates());
969 (generic_params, where_clauses)
970}
971
972#[derive(Debug)]
973struct ParamBoundWithParams {
974 node: ast::GenericParam,
975 self_ty_param: hir::GenericParam,
986 other_params: FxHashSet<hir::GenericParam>,
997}
998
999#[derive(Debug)]
1000struct WherePredWithParams {
1001 node: ast::WherePred,
1002 self_ty_params: FxHashSet<hir::GenericParam>,
1011 other_params: FxHashSet<hir::GenericParam>,
1020}
1021
1022fn compute_contained_params_in_generic_param(
1023 ctx: &AssistContext<'_, '_>,
1024 node: ast::GenericParam,
1025) -> Option<ParamBoundWithParams> {
1026 match &node {
1027 ast::GenericParam::TypeParam(ty) => {
1028 let self_ty_param = ctx.sema.to_def(ty)?.into();
1029
1030 let other_params = ty
1031 .type_bound_list()
1032 .into_iter()
1033 .flat_map(|it| it.bounds())
1034 .flat_map(|bound| bound.syntax().descendants())
1035 .filter_map(|node| filter_generic_params(ctx, node))
1036 .collect();
1037
1038 Some(ParamBoundWithParams { node, self_ty_param, other_params })
1039 }
1040 ast::GenericParam::ConstParam(ct) => {
1041 let self_ty_param = ctx.sema.to_def(ct)?.into();
1042 Some(ParamBoundWithParams { node, self_ty_param, other_params: FxHashSet::default() })
1043 }
1044 ast::GenericParam::LifetimeParam(_) => {
1045 None
1047 }
1048 }
1049}
1050
1051fn compute_contained_params_in_where_pred(
1052 ctx: &AssistContext<'_, '_>,
1053 node: ast::WherePred,
1054) -> Option<WherePredWithParams> {
1055 let self_ty = node.ty()?;
1056 let bound_list = node.type_bound_list()?;
1057
1058 let self_ty_params = self_ty
1059 .syntax()
1060 .descendants()
1061 .filter_map(|node| filter_generic_params(ctx, node))
1062 .collect();
1063
1064 let other_params = bound_list
1065 .bounds()
1066 .flat_map(|bound| bound.syntax().descendants())
1067 .filter_map(|node| filter_generic_params(ctx, node))
1068 .collect();
1069
1070 Some(WherePredWithParams { node, self_ty_params, other_params })
1071}
1072
1073fn filter_generic_params(
1074 ctx: &AssistContext<'_, '_>,
1075 node: SyntaxNode,
1076) -> Option<hir::GenericParam> {
1077 let path = ast::Path::cast(node)?;
1078 match ctx.sema.resolve_path(&path)? {
1079 PathResolution::TypeParam(it) => Some(it.into()),
1080 PathResolution::ConstParam(it) => Some(it.into()),
1081 _ => None,
1082 }
1083}
1084
1085fn filter_unnecessary_bounds(
1111 generic_params: &mut Vec<ParamBoundWithParams>,
1112 where_preds: &mut Vec<WherePredWithParams>,
1113 necessary_params: FxHashSet<hir::GenericParam>,
1114) {
1115 let param_map: FxHashMap<hir::GenericParam, usize> =
1117 generic_params.iter().map(|it| it.self_ty_param).zip(0..).collect();
1118 let param_count = param_map.len();
1119 let generic_params_upper_bound = param_count + generic_params.len();
1120 let node_count = generic_params_upper_bound + where_preds.len();
1121
1122 let mut graph = Graph::new(node_count);
1128 for (pred, pred_idx) in generic_params.iter().zip(param_count..) {
1129 let param_idx = param_map[&pred.self_ty_param];
1130 graph.add_edge(param_idx, pred_idx);
1131 graph.add_edge(pred_idx, param_idx);
1132
1133 for param in &pred.other_params {
1134 let param_idx = param_map[param];
1135 graph.add_edge(pred_idx, param_idx);
1136 }
1137 }
1138 for (pred, pred_idx) in where_preds.iter().zip(generic_params_upper_bound..) {
1139 for param in &pred.self_ty_params {
1140 let param_idx = param_map[param];
1141 graph.add_edge(param_idx, pred_idx);
1142 graph.add_edge(pred_idx, param_idx);
1143 }
1144 for param in &pred.other_params {
1145 let param_idx = param_map[param];
1146 graph.add_edge(pred_idx, param_idx);
1147 }
1148 }
1149
1150 let starting_nodes = necessary_params.iter().flat_map(|param| param_map.get(param).copied());
1151 let reachable = graph.compute_reachable_nodes(starting_nodes);
1152
1153 let mut idx = param_count;
1155 generic_params.retain(|_| {
1156 idx += 1;
1157 reachable[idx - 1]
1158 });
1159 stdx::always!(idx == generic_params_upper_bound, "inconsistent index");
1160 where_preds.retain(|_| {
1161 idx += 1;
1162 reachable[idx - 1]
1163 });
1164}
1165
1166fn filter_bounds_in_scope(
1169 generic_params: &mut Vec<ParamBoundWithParams>,
1170 where_preds: &mut Vec<WherePredWithParams>,
1171 ctx: &AssistContext<'_, '_>,
1172 target: &GeneratedFunctionTarget,
1173) -> Option<()> {
1174 let target_impl = target.parent().ancestors().find_map(ast::Impl::cast)?;
1175 let target_impl = ctx.sema.to_def(&target_impl)?;
1176 let def = generic_params.first()?.self_ty_param.parent();
1179 if def != hir::GenericDef::Impl(target_impl) {
1180 return None;
1181 }
1182
1183 generic_params.retain(|it| !matches!(it.self_ty_param.parent(), hir::GenericDef::Impl(_)));
1186 where_preds.retain(|it| {
1187 it.node.syntax().parent().and_then(|it| it.parent()).and_then(ast::Impl::cast).is_none()
1188 });
1189
1190 Some(())
1191}
1192
1193fn deduplicate_arg_names(arg_names: &mut [String]) {
1204 let mut arg_name_counts = FxHashMap::default();
1205 for name in arg_names.iter() {
1206 *arg_name_counts.entry(name).or_insert(0) += 1;
1207 }
1208 let duplicate_arg_names: FxHashSet<String> = arg_name_counts
1209 .into_iter()
1210 .filter(|(_, count)| *count >= 2)
1211 .map(|(name, _)| name.clone())
1212 .collect();
1213
1214 let mut counter_per_name = FxHashMap::default();
1215 for arg_name in arg_names.iter_mut() {
1216 if duplicate_arg_names.contains(arg_name) {
1217 let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
1218 arg_name.push('_');
1219 arg_name.push_str(&counter.to_string());
1220 *counter += 1;
1221 }
1222 }
1223}
1224
1225fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> String {
1226 let name = (|| match arg_expr {
1227 ast::Expr::CastExpr(cast_expr) => Some(fn_arg_name(sema, &cast_expr.expr()?)),
1228 expr => {
1229 let name_ref = expr
1230 .syntax()
1231 .descendants()
1232 .filter_map(ast::NameRef::cast)
1233 .filter(|name| name.ident_token().is_some())
1234 .last()?;
1235 if let Some(NameRefClass::Definition(Definition::Const(_) | Definition::Static(_), _)) =
1236 NameRefClass::classify(sema, &name_ref)
1237 {
1238 return Some(name_ref.to_string().to_lowercase());
1239 };
1240 Some(to_lower_snake_case(&name_ref.to_string()))
1241 }
1242 })();
1243 match name {
1244 Some(mut name) if name.starts_with(|c: char| c.is_ascii_digit()) => {
1245 name.insert_str(0, "arg");
1246 name
1247 }
1248 Some(name) => name,
1249 None => "arg".to_owned(),
1250 }
1251}
1252
1253fn fn_arg_type(
1254 ctx: &AssistContext<'_, '_>,
1255 target_module: Module,
1256 fn_arg: &ast::Expr,
1257 generic_params: &mut FxHashSet<hir::GenericParam>,
1258) -> String {
1259 fn maybe_displayed_type(
1260 ctx: &AssistContext<'_, '_>,
1261 target_module: Module,
1262 fn_arg: &ast::Expr,
1263 generic_params: &mut FxHashSet<hir::GenericParam>,
1264 ) -> Option<String> {
1265 let ty = ctx.sema.type_of_expr(fn_arg)?.adjusted();
1266 if ty.is_unknown() {
1267 return None;
1268 }
1269
1270 generic_params.extend(ty.generic_params(ctx.db()));
1271
1272 if ty.is_reference() || ty.is_mutable_reference() {
1273 let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
1274 convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
1275 .map(|conversion| conversion.convert_type(ctx.db(), target_module).to_string())
1276 .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
1277 } else {
1278 ty.display_source_code(ctx.db(), target_module.into(), true).ok()
1279 }
1280 }
1281
1282 maybe_displayed_type(ctx, target_module, fn_arg, generic_params)
1283 .unwrap_or_else(|| String::from("_"))
1284}
1285
1286fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<GeneratedFunctionTarget> {
1291 let mut ancestors = expr.syntax().ancestors().peekable();
1292 let mut last_ancestor: Option<SyntaxNode> = None;
1293 while let Some(next_ancestor) = ancestors.next() {
1294 match next_ancestor.kind() {
1295 SyntaxKind::SOURCE_FILE => {
1296 break;
1297 }
1298 SyntaxKind::ITEM_LIST
1299 if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) =>
1300 {
1301 break;
1302 }
1303 _ => {}
1304 }
1305 last_ancestor = Some(next_ancestor);
1306 }
1307 last_ancestor.map(GeneratedFunctionTarget::AfterItem)
1308}
1309
1310fn next_space_for_fn_in_module(
1311 db: &dyn hir::db::HirDatabase,
1312 target_module: hir::Module,
1313) -> (FileId, GeneratedFunctionTarget) {
1314 let module_source = target_module.definition_source(db);
1315 let file = module_source.file_id.original_file(db);
1316 let assist_item = match &module_source.value {
1317 hir::ModuleSource::SourceFile(it) => match it.items().last() {
1318 Some(last_item) => GeneratedFunctionTarget::AfterItem(last_item.syntax().clone()),
1319 None => GeneratedFunctionTarget::AfterItem(it.syntax().clone()),
1320 },
1321 hir::ModuleSource::Module(it) => match it.item_list().and_then(|it| it.items().last()) {
1322 Some(last_item) => GeneratedFunctionTarget::AfterItem(last_item.syntax().clone()),
1323 None => {
1324 let item_list =
1325 it.item_list().expect("module definition source should have an item list");
1326 GeneratedFunctionTarget::InEmptyItemList(item_list.syntax().clone())
1327 }
1328 },
1329 hir::ModuleSource::BlockExpr(it) => {
1330 if let Some(last_item) =
1331 it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
1332 {
1333 GeneratedFunctionTarget::AfterItem(last_item.syntax().clone())
1334 } else {
1335 GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
1336 }
1337 }
1338 };
1339
1340 (file.file_id(db), assist_item)
1341}
1342
1343#[derive(Clone, Copy)]
1344enum Visibility {
1345 None,
1346 Crate,
1347 Pub,
1348}
1349
1350fn calculate_necessary_visibility(
1351 current_module: Module,
1352 target_module: Module,
1353 ctx: &AssistContext<'_, '_>,
1354) -> Visibility {
1355 let db = ctx.db();
1356 let current_module = current_module.nearest_non_block_module(db);
1357 let target_module = target_module.nearest_non_block_module(db);
1358
1359 if target_module.krate(ctx.db()) != current_module.krate(ctx.db()) {
1360 Visibility::Pub
1361 } else if current_module.path_to_root(db).contains(&target_module) {
1362 Visibility::None
1363 } else {
1364 Visibility::Crate
1365 }
1366}
1367
1368struct Graph {
1372 edges: Vec<Vec<usize>>,
1373}
1374
1375impl Graph {
1376 fn new(node_count: usize) -> Self {
1377 Self { edges: vec![Vec::new(); node_count] }
1378 }
1379
1380 fn add_edge(&mut self, from: usize, to: usize) {
1381 self.edges[from].push(to);
1382 }
1383
1384 fn edges_for(&self, node_idx: usize) -> &[usize] {
1385 &self.edges[node_idx]
1386 }
1387
1388 fn len(&self) -> usize {
1389 self.edges.len()
1390 }
1391
1392 fn compute_reachable_nodes(
1393 &self,
1394 starting_nodes: impl IntoIterator<Item = usize>,
1395 ) -> Vec<bool> {
1396 let mut visitor = Visitor::new(self);
1397 for idx in starting_nodes {
1398 visitor.mark_reachable(idx);
1399 }
1400 visitor.visited
1401 }
1402}
1403
1404struct Visitor<'g> {
1405 graph: &'g Graph,
1406 visited: Vec<bool>,
1407 stack: Vec<usize>,
1409}
1410
1411impl<'g> Visitor<'g> {
1412 fn new(graph: &'g Graph) -> Self {
1413 let visited = vec![false; graph.len()];
1414 Self { graph, visited, stack: Vec::new() }
1415 }
1416
1417 fn mark_reachable(&mut self, start_idx: usize) {
1418 stdx::always!(self.stack.is_empty());
1420
1421 self.stack.push(start_idx);
1422 while let Some(idx) = self.stack.pop() {
1423 if !self.visited[idx] {
1424 self.visited[idx] = true;
1425 for &neighbor in self.graph.edges_for(idx) {
1426 if !self.visited[neighbor] {
1427 self.stack.push(neighbor);
1428 }
1429 }
1430 }
1431 }
1432 }
1433}
1434
1435#[cfg(test)]
1436mod tests {
1437 use crate::tests::{check_assist, check_assist_not_applicable};
1438
1439 use super::*;
1440
1441 #[test]
1442 fn add_function_with_no_args() {
1443 check_assist(
1444 generate_function,
1445 r"
1446fn foo() {
1447 bar$0();
1448}
1449",
1450 r"
1451fn foo() {
1452 bar();
1453}
1454
1455fn bar() ${0:-> _} {
1456 todo!()
1457}
1458",
1459 )
1460 }
1461
1462 #[test]
1463 fn add_function_from_method() {
1464 check_assist(
1467 generate_function,
1468 r"
1469impl Foo {
1470 fn foo() {
1471 bar$0();
1472 }
1473}
1474",
1475 r"
1476impl Foo {
1477 fn foo() {
1478 bar();
1479 }
1480}
1481
1482fn bar() ${0:-> _} {
1483 todo!()
1484}
1485",
1486 )
1487 }
1488
1489 #[test]
1490 fn add_function_directly_after_current_block() {
1491 check_assist(
1493 generate_function,
1494 r"
1495fn foo1() {
1496 bar$0();
1497}
1498
1499fn foo2() {}
1500",
1501 r"
1502fn foo1() {
1503 bar();
1504}
1505
1506fn bar() ${0:-> _} {
1507 todo!()
1508}
1509
1510fn foo2() {}
1511",
1512 )
1513 }
1514
1515 #[test]
1516 fn add_function_with_no_args_in_same_module() {
1517 check_assist(
1518 generate_function,
1519 r"
1520mod baz {
1521 fn foo() {
1522 bar$0();
1523 }
1524}
1525",
1526 r"
1527mod baz {
1528 fn foo() {
1529 bar();
1530 }
1531
1532 fn bar() ${0:-> _} {
1533 todo!()
1534 }
1535}
1536",
1537 )
1538 }
1539
1540 #[test]
1541 fn add_function_with_upper_camel_case_arg() {
1542 check_assist(
1543 generate_function,
1544 r"
1545struct BazBaz;
1546fn foo() {
1547 bar$0(BazBaz);
1548}
1549",
1550 r"
1551struct BazBaz;
1552fn foo() {
1553 bar(BazBaz);
1554}
1555
1556fn bar(baz_baz: BazBaz) ${0:-> _} {
1557 todo!()
1558}
1559",
1560 );
1561 }
1562
1563 #[test]
1564 fn add_function_with_upper_camel_case_arg_as_cast() {
1565 check_assist(
1566 generate_function,
1567 r"
1568struct BazBaz;
1569fn foo() {
1570 bar$0(&BazBaz as *const BazBaz);
1571}
1572",
1573 r"
1574struct BazBaz;
1575fn foo() {
1576 bar(&BazBaz as *const BazBaz);
1577}
1578
1579fn bar(baz_baz: *const BazBaz) ${0:-> _} {
1580 todo!()
1581}
1582",
1583 );
1584 }
1585
1586 #[test]
1587 fn add_function_with_function_call_arg() {
1588 check_assist(
1589 generate_function,
1590 r"
1591struct Baz;
1592fn baz() -> Baz { todo!() }
1593fn foo() {
1594 bar$0(baz());
1595}
1596",
1597 r"
1598struct Baz;
1599fn baz() -> Baz { todo!() }
1600fn foo() {
1601 bar(baz());
1602}
1603
1604fn bar(baz: Baz) ${0:-> _} {
1605 todo!()
1606}
1607",
1608 );
1609 }
1610
1611 #[test]
1612 fn add_function_with_method_call_arg() {
1613 check_assist(
1614 generate_function,
1615 r"
1616struct Baz;
1617impl Baz {
1618 fn foo(&self) -> Baz {
1619 ba$0r(self.baz())
1620 }
1621 fn baz(&self) -> Baz {
1622 Baz
1623 }
1624}
1625",
1626 r"
1627struct Baz;
1628impl Baz {
1629 fn foo(&self) -> Baz {
1630 bar(self.baz())
1631 }
1632 fn baz(&self) -> Baz {
1633 Baz
1634 }
1635}
1636
1637fn bar(baz: Baz) -> Baz {
1638 ${0:todo!()}
1639}
1640",
1641 )
1642 }
1643
1644 #[test]
1645 fn add_function_with_string_literal_arg() {
1646 check_assist(
1647 generate_function,
1648 r#"
1649fn foo() {
1650 $0bar("bar")
1651}
1652"#,
1653 r#"
1654fn foo() {
1655 bar("bar")
1656}
1657
1658fn bar(arg: &'static str) {
1659 ${0:todo!()}
1660}
1661"#,
1662 )
1663 }
1664
1665 #[test]
1666 fn add_function_with_char_literal_arg() {
1667 check_assist(
1668 generate_function,
1669 r#"
1670fn foo() {
1671 $0bar('x')
1672}
1673"#,
1674 r#"
1675fn foo() {
1676 bar('x')
1677}
1678
1679fn bar(arg: char) {
1680 ${0:todo!()}
1681}
1682"#,
1683 )
1684 }
1685
1686 #[test]
1687 fn add_function_with_int_literal_arg() {
1688 check_assist(
1689 generate_function,
1690 r"
1691fn foo() {
1692 $0bar(42)
1693}
1694",
1695 r"
1696fn foo() {
1697 bar(42)
1698}
1699
1700fn bar(arg: i32) {
1701 ${0:todo!()}
1702}
1703",
1704 )
1705 }
1706
1707 #[test]
1708 fn add_function_with_cast_int_literal_arg() {
1709 check_assist(
1710 generate_function,
1711 r"
1712fn foo() {
1713 $0bar(42 as u8)
1714}
1715",
1716 r"
1717fn foo() {
1718 bar(42 as u8)
1719}
1720
1721fn bar(arg: u8) {
1722 ${0:todo!()}
1723}
1724",
1725 )
1726 }
1727
1728 #[test]
1729 fn name_of_cast_variable_is_used() {
1730 check_assist(
1733 generate_function,
1734 r"
1735fn foo() {
1736 let x = 42;
1737 bar$0(x as u8)
1738}
1739",
1740 r"
1741fn foo() {
1742 let x = 42;
1743 bar(x as u8)
1744}
1745
1746fn bar(x: u8) {
1747 ${0:todo!()}
1748}
1749",
1750 )
1751 }
1752
1753 #[test]
1754 fn add_function_with_variable_arg() {
1755 check_assist(
1756 generate_function,
1757 r"
1758fn foo() {
1759 let worble = ();
1760 $0bar(worble)
1761}
1762",
1763 r"
1764fn foo() {
1765 let worble = ();
1766 bar(worble)
1767}
1768
1769fn bar(worble: ()) {
1770 ${0:todo!()}
1771}
1772",
1773 )
1774 }
1775
1776 #[test]
1777 fn add_function_with_impl_trait_arg() {
1778 check_assist(
1779 generate_function,
1780 r#"
1781//- minicore: sized
1782trait Foo {}
1783fn foo() -> impl Foo {
1784 todo!()
1785}
1786fn baz() {
1787 $0bar(foo())
1788}
1789"#,
1790 r#"
1791trait Foo {}
1792fn foo() -> impl Foo {
1793 todo!()
1794}
1795fn baz() {
1796 bar(foo())
1797}
1798
1799fn bar(foo: impl Foo) {
1800 ${0:todo!()}
1801}
1802"#,
1803 )
1804 }
1805
1806 #[test]
1807 fn borrowed_arg() {
1808 check_assist(
1809 generate_function,
1810 r"
1811struct Baz;
1812fn baz() -> Baz { todo!() }
1813
1814fn foo() {
1815 bar$0(&baz())
1816}
1817",
1818 r"
1819struct Baz;
1820fn baz() -> Baz { todo!() }
1821
1822fn foo() {
1823 bar(&baz())
1824}
1825
1826fn bar(baz: &Baz) {
1827 ${0:todo!()}
1828}
1829",
1830 )
1831 }
1832
1833 #[test]
1834 fn add_function_with_qualified_path_arg() {
1835 check_assist(
1836 generate_function,
1837 r"
1838mod Baz {
1839 pub struct Bof;
1840 pub fn baz() -> Bof { Bof }
1841}
1842fn foo() {
1843 $0bar(Baz::baz())
1844}
1845",
1846 r"
1847mod Baz {
1848 pub struct Bof;
1849 pub fn baz() -> Bof { Bof }
1850}
1851fn foo() {
1852 bar(Baz::baz())
1853}
1854
1855fn bar(baz: Baz::Bof) {
1856 ${0:todo!()}
1857}
1858",
1859 )
1860 }
1861
1862 #[test]
1863 fn generate_function_with_generic_param() {
1864 check_assist(
1865 generate_function,
1866 r"
1867fn foo<T, const N: usize>(t: [T; N]) { $0bar(t) }
1868",
1869 r"
1870fn foo<T, const N: usize>(t: [T; N]) { bar(t) }
1871
1872fn bar<T, const N: usize>(t: [T; N]) {
1873 ${0:todo!()}
1874}
1875",
1876 )
1877 }
1878
1879 #[test]
1880 fn generate_function_with_parent_generic_param() {
1881 check_assist(
1882 generate_function,
1883 r"
1884struct S<T>(T);
1885impl<T> S<T> {
1886 fn foo<U>(t: T, u: U) { $0bar(t, u) }
1887}
1888",
1889 r"
1890struct S<T>(T);
1891impl<T> S<T> {
1892 fn foo<U>(t: T, u: U) { bar(t, u) }
1893}
1894
1895fn bar<T, U>(t: T, u: U) {
1896 ${0:todo!()}
1897}
1898",
1899 )
1900 }
1901
1902 #[test]
1903 fn generic_param_in_receiver_type() {
1904 check_assist(
1906 generate_function,
1907 r"
1908struct S<T>(T);
1909fn foo<T, U>(s: S<T>, u: U) { s.$0foo(u) }
1910",
1911 r"
1912struct S<T>(T);
1913impl S {
1914 fn foo<T, U>(&self, u: U) {
1915 ${0:todo!()}
1916 }
1917}
1918fn foo<T, U>(s: S<T>, u: U) { s.foo(u) }
1919",
1920 )
1921 }
1922
1923 #[test]
1924 fn generic_param_in_return_type() {
1925 check_assist(
1926 generate_function,
1927 r"
1928fn foo<T, const N: usize>() -> [T; N] { $0bar() }
1929",
1930 r"
1931fn foo<T, const N: usize>() -> [T; N] { bar() }
1932
1933fn bar<T, const N: usize>() -> [T; N] {
1934 ${0:todo!()}
1935}
1936",
1937 )
1938 }
1939
1940 #[test]
1941 fn generate_fn_with_bounds() {
1942 check_assist(
1944 generate_function,
1945 r"
1946trait A<T> {}
1947struct S<T>(T);
1948impl<T: A<i32>> S<T>
1949where
1950 T: A<i64>,
1951{
1952 fn foo<U>(t: T, u: U)
1953 where
1954 T: A<()>,
1955 U: A<i32> + A<i64>,
1956 {
1957 $0bar(t, u)
1958 }
1959}
1960",
1961 r"
1962trait A<T> {}
1963struct S<T>(T);
1964impl<T: A<i32>> S<T>
1965where
1966 T: A<i64>,
1967{
1968 fn foo<U>(t: T, u: U)
1969 where
1970 T: A<()>,
1971 U: A<i32> + A<i64>,
1972 {
1973 bar(t, u)
1974 }
1975}
1976
1977fn bar<T: A<i32>, U>(t: T, u: U) where T: A<i64>, T: A<()>, U: A<i32> + A<i64> {
1978 ${0:todo!()}
1979}
1980",
1981 )
1982 }
1983
1984 #[test]
1985 fn include_transitive_param_dependency() {
1986 check_assist(
1988 generate_function,
1989 r"
1990trait A<T> { type Assoc; }
1991trait B { type Item; }
1992struct S<T>(T);
1993impl<T, U, V: B, W> S<(T, U, V, W)>
1994where
1995 T: A<U, Assoc = V>,
1996 S<V::Item>: A<U, Assoc = W>,
1997{
1998 fn foo<I>(t: T, u: U)
1999 where
2000 U: A<T, Assoc = I>,
2001 {
2002 $0bar(u)
2003 }
2004}
2005",
2006 r"
2007trait A<T> { type Assoc; }
2008trait B { type Item; }
2009struct S<T>(T);
2010impl<T, U, V: B, W> S<(T, U, V, W)>
2011where
2012 T: A<U, Assoc = V>,
2013 S<V::Item>: A<U, Assoc = W>,
2014{
2015 fn foo<I>(t: T, u: U)
2016 where
2017 U: A<T, Assoc = I>,
2018 {
2019 bar(u)
2020 }
2021}
2022
2023fn bar<T, U, V: B, W, I>(u: U) where T: A<U, Assoc = V>, S<V::Item>: A<U, Assoc = W>, U: A<T, Assoc = I> {
2024 ${0:todo!()}
2025}
2026",
2027 )
2028 }
2029
2030 #[test]
2031 fn irrelevant_bounds_are_filtered_out() {
2032 check_assist(
2033 generate_function,
2034 r"
2035trait A<T> {}
2036struct S<T>(T);
2037impl<T, U, V, W> S<(T, U, V, W)>
2038where
2039 T: A<U>,
2040 V: A<W>,
2041{
2042 fn foo<I>(t: T, u: U)
2043 where
2044 U: A<T> + A<I>,
2045 {
2046 $0bar(u)
2047 }
2048}
2049",
2050 r"
2051trait A<T> {}
2052struct S<T>(T);
2053impl<T, U, V, W> S<(T, U, V, W)>
2054where
2055 T: A<U>,
2056 V: A<W>,
2057{
2058 fn foo<I>(t: T, u: U)
2059 where
2060 U: A<T> + A<I>,
2061 {
2062 bar(u)
2063 }
2064}
2065
2066fn bar<T, U, I>(u: U) where T: A<U>, U: A<T> + A<I> {
2067 ${0:todo!()}
2068}
2069",
2070 )
2071 }
2072
2073 #[test]
2074 fn params_in_trait_arg_are_not_dependency() {
2075 check_assist(
2078 generate_function,
2079 r"
2080trait A<T> {}
2081struct S<T>(T);
2082impl<T, U> S<(T, U)>
2083where
2084 T: A<U>,
2085{
2086 fn foo<I>(t: T, u: U)
2087 where
2088 T: A<I>,
2089 U: A<I>,
2090 {
2091 $0bar(u)
2092 }
2093}
2094",
2095 r"
2096trait A<T> {}
2097struct S<T>(T);
2098impl<T, U> S<(T, U)>
2099where
2100 T: A<U>,
2101{
2102 fn foo<I>(t: T, u: U)
2103 where
2104 T: A<I>,
2105 U: A<I>,
2106 {
2107 bar(u)
2108 }
2109}
2110
2111fn bar<U, I>(u: U) where U: A<I> {
2112 ${0:todo!()}
2113}
2114",
2115 )
2116 }
2117
2118 #[test]
2119 fn dont_copy_bounds_already_in_scope() {
2120 check_assist(
2121 generate_function,
2122 r"
2123trait A<T> {}
2124struct S<T>(T);
2125impl<T: A<i32>> S<T>
2126where
2127 T: A<usize>,
2128{
2129 fn foo<U: A<()>>(t: T, u: U)
2130 where
2131 T: A<S<i32>>,
2132 {
2133 Self::$0bar(t, u);
2134 }
2135}
2136",
2137 r"
2138trait A<T> {}
2139struct S<T>(T);
2140impl<T: A<i32>> S<T>
2141where
2142 T: A<usize>,
2143{
2144 fn foo<U: A<()>>(t: T, u: U)
2145 where
2146 T: A<S<i32>>,
2147 {
2148 Self::bar(t, u);
2149 }
2150
2151 fn bar<U: A<()>>(t: T, u: U) ${0:-> _} where T: A<S<i32>> {
2152 todo!()
2153 }
2154}
2155",
2156 )
2157 }
2158
2159 #[test]
2160 fn add_function_with_fn_arg() {
2161 check_assist(
2162 generate_function,
2163 r"
2164struct Baz;
2165impl Baz {
2166 fn new() -> Self { Baz }
2167}
2168fn foo() {
2169 $0bar(Baz::new);
2170}
2171",
2172 r"
2173struct Baz;
2174impl Baz {
2175 fn new() -> Self { Baz }
2176}
2177fn foo() {
2178 bar(Baz::new);
2179}
2180
2181fn bar(new: fn() -> Baz) ${0:-> _} {
2182 todo!()
2183}
2184",
2185 )
2186 }
2187
2188 #[test]
2189 fn add_function_with_closure_arg() {
2190 check_assist(
2191 generate_function,
2192 r"
2193fn foo() {
2194 let closure = |x: i64| x - 1;
2195 $0bar(closure)
2196}
2197",
2198 r"
2199fn foo() {
2200 let closure = |x: i64| x - 1;
2201 bar(closure)
2202}
2203
2204fn bar(closure: impl Fn(i64) -> i64) {
2205 ${0:todo!()}
2206}
2207",
2208 )
2209 }
2210
2211 #[test]
2212 fn unresolvable_types_default_to_placeholder() {
2213 check_assist(
2214 generate_function,
2215 r"
2216fn foo() {
2217 $0bar(baz)
2218}
2219",
2220 r"
2221fn foo() {
2222 bar(baz)
2223}
2224
2225fn bar(baz: _) {
2226 ${0:todo!()}
2227}
2228",
2229 )
2230 }
2231
2232 #[test]
2233 fn arg_names_dont_overlap() {
2234 check_assist(
2235 generate_function,
2236 r"
2237struct Baz;
2238fn baz() -> Baz { Baz }
2239fn foo() {
2240 $0bar(baz(), baz())
2241}
2242",
2243 r"
2244struct Baz;
2245fn baz() -> Baz { Baz }
2246fn foo() {
2247 bar(baz(), baz())
2248}
2249
2250fn bar(baz_1: Baz, baz_2: Baz) {
2251 ${0:todo!()}
2252}
2253",
2254 )
2255 }
2256
2257 #[test]
2258 fn arg_name_counters_start_at_1_per_name() {
2259 check_assist(
2260 generate_function,
2261 r#"
2262struct Baz;
2263fn baz() -> Baz { Baz }
2264fn foo() {
2265 $0bar(baz(), baz(), "foo", "bar")
2266}
2267"#,
2268 r#"
2269struct Baz;
2270fn baz() -> Baz { Baz }
2271fn foo() {
2272 bar(baz(), baz(), "foo", "bar")
2273}
2274
2275fn bar(baz_1: Baz, baz_2: Baz, arg_1: &'static str, arg_2: &'static str) {
2276 ${0:todo!()}
2277}
2278"#,
2279 )
2280 }
2281
2282 #[test]
2283 fn add_function_in_module() {
2284 check_assist(
2285 generate_function,
2286 r"
2287mod bar {}
2288
2289fn foo() {
2290 bar::my_fn$0()
2291}
2292",
2293 r"
2294mod bar {
2295 pub(crate) fn my_fn() {
2296 ${0:todo!()}
2297 }
2298}
2299
2300fn foo() {
2301 bar::my_fn()
2302}
2303",
2304 )
2305 }
2306
2307 #[test]
2308 fn qualified_path_uses_correct_scope() {
2309 check_assist(
2310 generate_function,
2311 r#"
2312mod foo {
2313 pub struct Foo;
2314}
2315fn bar() {
2316 use foo::Foo;
2317 let foo = Foo;
2318 baz$0(foo)
2319}
2320"#,
2321 r#"
2322mod foo {
2323 pub struct Foo;
2324}
2325fn bar() {
2326 use foo::Foo;
2327 let foo = Foo;
2328 baz(foo)
2329}
2330
2331fn baz(foo: foo::Foo) {
2332 ${0:todo!()}
2333}
2334"#,
2335 )
2336 }
2337
2338 #[test]
2339 fn qualified_path_in_generic_bounds_uses_correct_scope() {
2340 check_assist(
2341 generate_function,
2342 r"
2343mod a {
2344 pub trait A {};
2345}
2346pub mod b {
2347 pub struct S<T>(T);
2348}
2349struct S<T>(T);
2350impl<T> S<T>
2351where
2352 T: a::A,
2353{
2354 fn foo<U: a::A>(t: b::S<T>, u: S<U>) {
2355 a::$0bar(t, u);
2356 }
2357}
2358",
2359 r"
2360mod a {
2361 pub trait A {}
2362
2363 pub(crate) fn bar<T, U: self::A>(t: crate::b::S<T>, u: crate::S<U>) ${0:-> _} where T: self::A {
2364 todo!()
2365 };
2366}
2367pub mod b {
2368 pub struct S<T>(T);
2369}
2370struct S<T>(T);
2371impl<T> S<T>
2372where
2373 T: a::A,
2374{
2375 fn foo<U: a::A>(t: b::S<T>, u: S<U>) {
2376 a::bar(t, u);
2377 }
2378}
2379",
2380 )
2381 }
2382 #[test]
2383 fn add_function_in_module_containing_other_items() {
2384 check_assist(
2385 generate_function,
2386 r"
2387mod bar {
2388 fn something_else() {}
2389}
2390
2391fn foo() {
2392 bar::my_fn$0()
2393}
2394",
2395 r"
2396mod bar {
2397 fn something_else() {}
2398
2399 pub(crate) fn my_fn() {
2400 ${0:todo!()}
2401 }
2402}
2403
2404fn foo() {
2405 bar::my_fn()
2406}
2407",
2408 )
2409 }
2410
2411 #[test]
2412 fn add_function_in_nested_module() {
2413 check_assist(
2414 generate_function,
2415 r"
2416mod bar {
2417 pub mod baz {}
2418}
2419
2420fn foo() {
2421 bar::baz::my_fn$0()
2422}
2423",
2424 r"
2425mod bar {
2426 pub mod baz {
2427 pub(crate) fn my_fn() {
2428 ${0:todo!()}
2429 }
2430 }
2431}
2432
2433fn foo() {
2434 bar::baz::my_fn()
2435}
2436",
2437 )
2438 }
2439
2440 #[test]
2441 fn add_function_in_another_file() {
2442 check_assist(
2443 generate_function,
2444 r"
2445//- /main.rs
2446mod foo;
2447
2448fn main() {
2449 foo::bar$0()
2450}
2451//- /foo.rs
2452",
2453 r"
2454
2455
2456pub(crate) fn bar() {
2457 ${0:todo!()}
2458}",
2459 )
2460 }
2461
2462 #[test]
2463 fn add_function_with_return_type() {
2464 check_assist(
2465 generate_function,
2466 r"
2467fn main() {
2468 let x: u32 = foo$0();
2469}
2470",
2471 r"
2472fn main() {
2473 let x: u32 = foo();
2474}
2475
2476fn foo() -> u32 {
2477 ${0:todo!()}
2478}
2479",
2480 )
2481 }
2482
2483 #[test]
2484 fn add_function_not_applicable_if_function_already_exists() {
2485 check_assist_not_applicable(
2486 generate_function,
2487 r"
2488fn foo() {
2489 bar$0();
2490}
2491
2492fn bar() {}
2493",
2494 )
2495 }
2496
2497 #[test]
2498 fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
2499 check_assist_not_applicable(
2500 generate_function,
2504 r#"
2505fn foo() {
2506 bar(b$0az);
2507}
2508
2509fn bar(baz: ()) {}
2510"#,
2511 )
2512 }
2513
2514 #[test]
2515 fn create_method_with_no_args() {
2516 check_assist(
2517 generate_function,
2518 r#"
2519struct Foo;
2520impl Foo {
2521 fn foo(&self) {
2522 self.bar()$0;
2523 }
2524}
2525"#,
2526 r#"
2527struct Foo;
2528impl Foo {
2529 fn foo(&self) {
2530 self.bar();
2531 }
2532
2533 fn bar(&self) ${0:-> _} {
2534 todo!()
2535 }
2536}
2537"#,
2538 )
2539 }
2540
2541 #[test]
2542 fn create_method_with_unused_generics() {
2543 check_assist(
2544 generate_function,
2545 r#"
2546struct Foo<S>(S);
2547impl<S> Foo<S> {
2548 fn foo(&self) {
2549 self.bar()$0;
2550 }
2551}
2552"#,
2553 r#"
2554struct Foo<S>(S);
2555impl<S> Foo<S> {
2556 fn foo(&self) {
2557 self.bar();
2558 }
2559
2560 fn bar(&self) ${0:-> _} {
2561 todo!()
2562 }
2563}
2564"#,
2565 )
2566 }
2567
2568 #[test]
2569 fn create_function_with_async() {
2570 check_assist(
2571 generate_function,
2572 r"
2573async fn foo() {
2574 $0bar(42).await;
2575}
2576",
2577 r"
2578async fn foo() {
2579 bar(42).await;
2580}
2581
2582async fn bar(arg: i32) ${0:-> _} {
2583 todo!()
2584}
2585",
2586 )
2587 }
2588
2589 #[test]
2590 fn return_type_for_async_fn() {
2591 check_assist(
2592 generate_function,
2593 r"
2594//- minicore: result
2595async fn foo() {
2596 if Err(()) = $0bar(42).await {}
2597}
2598",
2599 r"
2600async fn foo() {
2601 if Err(()) = bar(42).await {}
2602}
2603
2604async fn bar(arg: i32) -> Result<_, ()> {
2605 ${0:todo!()}
2606}
2607",
2608 );
2609 }
2610
2611 #[test]
2612 fn create_method() {
2613 check_assist(
2614 generate_function,
2615 r"
2616struct S;
2617fn foo() {S.bar$0();}
2618",
2619 r"
2620struct S;
2621impl S {
2622 fn bar(&self) ${0:-> _} {
2623 todo!()
2624 }
2625}
2626fn foo() {S.bar();}
2627",
2628 )
2629 }
2630
2631 #[test]
2632 fn create_method_within_an_impl() {
2633 check_assist(
2634 generate_function,
2635 r"
2636struct S;
2637fn foo() {S.bar$0();}
2638impl S {}
2639
2640",
2641 r"
2642struct S;
2643fn foo() {S.bar();}
2644impl S {
2645 fn bar(&self) ${0:-> _} {
2646 todo!()
2647 }
2648}
2649
2650",
2651 )
2652 }
2653
2654 #[test]
2655 fn create_method_from_different_module() {
2656 check_assist(
2657 generate_function,
2658 r"
2659mod s {
2660 pub struct S;
2661}
2662fn foo() {s::S.bar$0();}
2663",
2664 r"
2665mod s {
2666 pub struct S;
2667 impl S {
2668 pub(crate) fn bar(&self) ${0:-> _} {
2669 todo!()
2670 }
2671 }
2672}
2673fn foo() {s::S.bar();}
2674",
2675 )
2676 }
2677
2678 #[test]
2679 fn create_method_from_descendant_module() {
2680 check_assist(
2681 generate_function,
2682 r"
2683struct S;
2684mod s {
2685 fn foo() {
2686 super::S.bar$0();
2687 }
2688}
2689
2690",
2691 r"
2692struct S;
2693impl S {
2694 fn bar(&self) ${0:-> _} {
2695 todo!()
2696 }
2697}
2698mod s {
2699 fn foo() {
2700 super::S.bar();
2701 }
2702}
2703
2704",
2705 )
2706 }
2707
2708 #[test]
2709 fn create_method_with_cursor_anywhere_on_call_expression() {
2710 check_assist(
2711 generate_function,
2712 r"
2713struct S;
2714fn foo() {$0S.bar();}
2715",
2716 r"
2717struct S;
2718impl S {
2719 fn bar(&self) ${0:-> _} {
2720 todo!()
2721 }
2722}
2723fn foo() {S.bar();}
2724",
2725 )
2726 }
2727
2728 #[test]
2729 fn create_async_method() {
2730 check_assist(
2731 generate_function,
2732 r"
2733//- minicore: result
2734struct S;
2735async fn foo() {
2736 if let Err(()) = S.$0bar(42).await {}
2737}
2738",
2739 r"
2740struct S;
2741impl S {
2742 async fn bar(&self, arg: i32) -> Result<_, ()> {
2743 ${0:todo!()}
2744 }
2745}
2746async fn foo() {
2747 if let Err(()) = S.bar(42).await {}
2748}
2749",
2750 )
2751 }
2752
2753 #[test]
2754 fn create_static_method() {
2755 check_assist(
2756 generate_function,
2757 r"
2758struct S;
2759fn foo() {S::bar$0();}
2760",
2761 r"
2762struct S;
2763impl S {
2764 fn bar() ${0:-> _} {
2765 todo!()
2766 }
2767}
2768fn foo() {S::bar();}
2769",
2770 )
2771 }
2772
2773 #[test]
2774 fn create_async_static_method() {
2775 check_assist(
2776 generate_function,
2777 r"
2778//- minicore: result
2779struct S;
2780async fn foo() {
2781 if let Err(()) = S::$0bar(42).await {}
2782}
2783",
2784 r"
2785struct S;
2786impl S {
2787 async fn bar(arg: i32) -> Result<_, ()> {
2788 ${0:todo!()}
2789 }
2790}
2791async fn foo() {
2792 if let Err(()) = S::bar(42).await {}
2793}
2794",
2795 )
2796 }
2797
2798 #[test]
2799 fn create_generic_static_method() {
2800 check_assist(
2801 generate_function,
2802 r"
2803struct S;
2804fn foo<T, const N: usize>(t: [T; N]) { S::bar$0(t); }
2805",
2806 r"
2807struct S;
2808impl S {
2809 fn bar<T, const N: usize>(t: [T; N]) ${0:-> _} {
2810 todo!()
2811 }
2812}
2813fn foo<T, const N: usize>(t: [T; N]) { S::bar(t); }
2814",
2815 )
2816 }
2817
2818 #[test]
2819 fn create_static_method_within_an_impl() {
2820 check_assist(
2821 generate_function,
2822 r"
2823struct S;
2824fn foo() {S::bar$0();}
2825impl S {}
2826
2827",
2828 r"
2829struct S;
2830fn foo() {S::bar();}
2831impl S {
2832 fn bar() ${0:-> _} {
2833 todo!()
2834 }
2835}
2836
2837",
2838 )
2839 }
2840
2841 #[test]
2842 fn create_static_method_from_different_module() {
2843 check_assist(
2844 generate_function,
2845 r"
2846mod s {
2847 pub struct S;
2848}
2849fn foo() {s::S::bar$0();}
2850",
2851 r"
2852mod s {
2853 pub struct S;
2854 impl S {
2855 pub(crate) fn bar() ${0:-> _} {
2856 todo!()
2857 }
2858 }
2859}
2860fn foo() {s::S::bar();}
2861",
2862 )
2863 }
2864
2865 #[test]
2866 fn create_static_method_with_cursor_anywhere_on_call_expression() {
2867 check_assist(
2868 generate_function,
2869 r"
2870struct S;
2871fn foo() {$0S::bar();}
2872",
2873 r"
2874struct S;
2875impl S {
2876 fn bar() ${0:-> _} {
2877 todo!()
2878 }
2879}
2880fn foo() {S::bar();}
2881",
2882 )
2883 }
2884
2885 #[test]
2886 fn create_static_method_within_an_impl_with_self_syntax() {
2887 check_assist(
2888 generate_function,
2889 r"
2890struct S;
2891impl S {
2892 fn foo(&self) {
2893 Self::bar$0();
2894 }
2895}
2896",
2897 r"
2898struct S;
2899impl S {
2900 fn foo(&self) {
2901 Self::bar();
2902 }
2903
2904 fn bar() ${0:-> _} {
2905 todo!()
2906 }
2907}
2908",
2909 )
2910 }
2911
2912 #[test]
2913 fn no_panic_on_invalid_global_path() {
2914 check_assist(
2915 generate_function,
2916 r"
2917fn main() {
2918 ::foo$0();
2919}
2920",
2921 r"
2922fn main() {
2923 ::foo();
2924}
2925
2926fn foo() ${0:-> _} {
2927 todo!()
2928}
2929",
2930 )
2931 }
2932
2933 #[test]
2934 fn handle_tuple_indexing() {
2935 check_assist(
2936 generate_function,
2937 r"
2938fn main() {
2939 let a = ((),);
2940 foo$0(a.0);
2941}
2942",
2943 r"
2944fn main() {
2945 let a = ((),);
2946 foo(a.0);
2947}
2948
2949fn foo(a: ()) ${0:-> _} {
2950 todo!()
2951}
2952",
2953 )
2954 }
2955
2956 #[test]
2957 fn add_function_with_const_arg() {
2958 check_assist(
2959 generate_function,
2960 r"
2961const VALUE: usize = 0;
2962fn main() {
2963 foo$0(VALUE);
2964}
2965",
2966 r"
2967const VALUE: usize = 0;
2968fn main() {
2969 foo(VALUE);
2970}
2971
2972fn foo(value: usize) ${0:-> _} {
2973 todo!()
2974}
2975",
2976 )
2977 }
2978
2979 #[test]
2980 fn add_function_with_static_arg() {
2981 check_assist(
2982 generate_function,
2983 r"
2984static VALUE: usize = 0;
2985fn main() {
2986 foo$0(VALUE);
2987}
2988",
2989 r"
2990static VALUE: usize = 0;
2991fn main() {
2992 foo(VALUE);
2993}
2994
2995fn foo(value: usize) ${0:-> _} {
2996 todo!()
2997}
2998",
2999 )
3000 }
3001
3002 #[test]
3003 fn add_function_with_static_mut_arg() {
3004 check_assist(
3005 generate_function,
3006 r"
3007static mut VALUE: usize = 0;
3008fn main() {
3009 foo$0(VALUE);
3010}
3011",
3012 r"
3013static mut VALUE: usize = 0;
3014fn main() {
3015 foo(VALUE);
3016}
3017
3018fn foo(value: usize) ${0:-> _} {
3019 todo!()
3020}
3021",
3022 )
3023 }
3024
3025 #[test]
3026 fn not_applicable_for_enum_variant() {
3027 check_assist_not_applicable(
3028 generate_function,
3029 r"
3030enum Foo {}
3031fn main() {
3032 Foo::Bar$0(true)
3033}
3034",
3035 );
3036 }
3037
3038 #[test]
3039 fn applicable_for_enum_method() {
3040 check_assist(
3041 generate_function,
3042 r"
3043enum Foo {}
3044fn main() {
3045 Foo::bar$0();
3046}
3047",
3048 r"
3049enum Foo {}
3050impl Foo {
3051 fn bar() ${0:-> _} {
3052 todo!()
3053 }
3054}
3055fn main() {
3056 Foo::bar();
3057}
3058",
3059 )
3060 }
3061
3062 #[test]
3063 fn applicable_in_different_local_crate() {
3064 check_assist(
3065 generate_function,
3066 r"
3067//- /lib.rs crate:lib new_source_root:local
3068fn dummy() {}
3069//- /main.rs crate:main deps:lib new_source_root:local
3070fn main() {
3071 lib::foo$0();
3072}
3073",
3074 r"
3075fn dummy() {}
3076
3077pub fn foo() ${0:-> _} {
3078 todo!()
3079}
3080",
3081 );
3082 }
3083
3084 #[test]
3085 fn applicable_in_different_local_crate_method() {
3086 check_assist(
3087 generate_function,
3088 r"
3089//- /lib.rs crate:lib new_source_root:local
3090pub struct S;
3091//- /main.rs crate:main deps:lib new_source_root:local
3092fn main() {
3093 lib::S.foo$0();
3094}
3095",
3096 r"
3097pub struct S;
3098impl S {
3099 pub fn foo(&self) ${0:-> _} {
3100 todo!()
3101 }
3102}
3103",
3104 );
3105 }
3106
3107 #[test]
3108 fn not_applicable_in_different_library_crate() {
3109 check_assist_not_applicable(
3110 generate_function,
3111 r"
3112//- /lib.rs crate:lib new_source_root:library
3113fn dummy() {}
3114//- /main.rs crate:main deps:lib new_source_root:local
3115fn main() {
3116 lib::foo$0();
3117}
3118",
3119 );
3120 }
3121
3122 #[test]
3123 fn not_applicable_in_different_library_crate_method() {
3124 check_assist_not_applicable(
3125 generate_function,
3126 r"
3127//- /lib.rs crate:lib new_source_root:library
3128pub struct S;
3129//- /main.rs crate:main deps:lib new_source_root:local
3130fn main() {
3131 lib::S.foo$0();
3132}
3133",
3134 );
3135 }
3136
3137 #[test]
3138 fn new_function_assume_self_type() {
3139 check_assist(
3140 generate_function,
3141 r"
3142pub struct Foo {
3143 field_1: usize,
3144 field_2: String,
3145}
3146
3147fn main() {
3148 let foo = Foo::new$0();
3149}
3150 ",
3151 r"
3152pub struct Foo {
3153 field_1: usize,
3154 field_2: String,
3155}
3156impl Foo {
3157 fn new() -> Self {
3158 ${0:Self { field_1: todo!(), field_2: todo!() }}
3159 }
3160}
3161
3162fn main() {
3163 let foo = Foo::new();
3164}
3165 ",
3166 )
3167 }
3168
3169 #[test]
3170 fn new_function_assume_self_type_for_tuple_struct() {
3171 check_assist(
3172 generate_function,
3173 r"
3174pub struct Foo (usize, String);
3175
3176fn main() {
3177 let foo = Foo::new$0();
3178}
3179 ",
3180 r"
3181pub struct Foo (usize, String);
3182impl Foo {
3183 fn new() -> Self {
3184 ${0:Self(todo!(), todo!())}
3185 }
3186}
3187
3188fn main() {
3189 let foo = Foo::new();
3190}
3191 ",
3192 )
3193 }
3194
3195 #[test]
3196 fn new_function_assume_self_type_for_unit_struct() {
3197 check_assist(
3198 generate_function,
3199 r"
3200pub struct Foo;
3201
3202fn main() {
3203 let foo = Foo::new$0();
3204}
3205 ",
3206 r"
3207pub struct Foo;
3208impl Foo {
3209 fn new() -> Self {
3210 ${0:Self}
3211 }
3212}
3213
3214fn main() {
3215 let foo = Foo::new();
3216}
3217 ",
3218 )
3219 }
3220
3221 #[test]
3222 fn new_function_assume_self_type_for_enum() {
3223 check_assist(
3224 generate_function,
3225 r"
3226pub enum Foo {}
3227
3228fn main() {
3229 let foo = Foo::new$0();
3230}
3231 ",
3232 r"
3233pub enum Foo {}
3234impl Foo {
3235 fn new() -> Self {
3236 ${0:todo!()}
3237 }
3238}
3239
3240fn main() {
3241 let foo = Foo::new();
3242}
3243 ",
3244 )
3245 }
3246
3247 #[test]
3248 fn new_function_assume_self_type_with_args() {
3249 check_assist(
3250 generate_function,
3251 r#"
3252pub struct Foo {
3253 field_1: usize,
3254 field_2: String,
3255}
3256
3257struct Baz;
3258fn baz() -> Baz { Baz }
3259
3260fn main() {
3261 let foo = Foo::new$0(baz(), baz(), "foo", "bar");
3262}
3263 "#,
3264 r#"
3265pub struct Foo {
3266 field_1: usize,
3267 field_2: String,
3268}
3269impl Foo {
3270 fn new(baz_1: Baz, baz_2: Baz, arg_1: &'static str, arg_2: &'static str) -> Self {
3271 ${0:Self { field_1: todo!(), field_2: todo!() }}
3272 }
3273}
3274
3275struct Baz;
3276fn baz() -> Baz { Baz }
3277
3278fn main() {
3279 let foo = Foo::new(baz(), baz(), "foo", "bar");
3280}
3281 "#,
3282 )
3283 }
3284
3285 #[test]
3286 fn no_generate_method_by_keyword() {
3287 check_assist_not_applicable(
3288 generate_function,
3289 r#"
3290fn main() {
3291 s.super$0();
3292}
3293 "#,
3294 );
3295 check_assist_not_applicable(
3296 generate_function,
3297 r#"
3298fn main() {
3299 s.Self$0();
3300}
3301 "#,
3302 );
3303 check_assist_not_applicable(
3304 generate_function,
3305 r#"
3306fn main() {
3307 s.self$0();
3308}
3309 "#,
3310 );
3311 }
3312
3313 #[test]
3314 fn regression_21288() {
3315 check_assist(
3316 generate_function,
3317 r#"
3318//- minicore: copy
3319fn foo() {
3320 $0bar(&|x| true)
3321}
3322 "#,
3323 r#"
3324fn foo() {
3325 bar(&|x| true)
3326}
3327
3328fn bar(arg: impl Fn(_) -> bool) {
3329 ${0:todo!()}
3330}
3331 "#,
3332 );
3333 }
3334 #[test]
3335 fn generate_method_uses_current_impl_block() {
3336 check_assist(
3337 generate_function,
3338 r"
3339struct Foo;
3340
3341impl Foo {
3342 fn new() -> Self {
3343 Foo
3344 }
3345}
3346
3347impl Foo {
3348 fn method1(&self) {
3349 self.method2$0(42)
3350 }
3351}
3352",
3353 r"
3354struct Foo;
3355
3356impl Foo {
3357 fn new() -> Self {
3358 Foo
3359 }
3360}
3361
3362impl Foo {
3363 fn method1(&self) {
3364 self.method2(42)
3365 }
3366
3367 fn method2(&self, arg: i32) {
3368 ${0:todo!()}
3369 }
3370}
3371",
3372 )
3373 }
3374
3375 #[test]
3376 fn generate_method_skips_trait_impl_for_inherent() {
3377 check_assist(
3379 generate_function,
3380 r"
3381struct Bar;
3382
3383impl Bar {
3384 fn func1() {}
3385}
3386
3387trait Foo { fn foo(&self); }
3388
3389impl Foo for Bar {
3390 fn foo(&self) {
3391 self.func2$0();
3392 }
3393}
3394",
3395 r"
3396struct Bar;
3397
3398impl Bar {
3399 fn func1() {}
3400
3401 fn func2(&self) ${0:-> _} {
3402 todo!()
3403 }
3404}
3405
3406trait Foo { fn foo(&self); }
3407
3408impl Foo for Bar {
3409 fn foo(&self) {
3410 self.func2();
3411 }
3412}
3413",
3414 )
3415 }
3416
3417 #[test]
3418 fn generate_method_from_trait_impl_creates_new_inherent_impl() {
3419 check_assist(
3422 generate_function,
3423 r"
3424struct Bar;
3425
3426trait Foo { fn foo(&self); }
3427
3428impl Foo for Bar {
3429 fn foo(&self) {
3430 self.func2$0();
3431 }
3432}
3433",
3434 r"
3435struct Bar;
3436impl Bar {
3437 fn func2(&self) ${0:-> _} {
3438 todo!()
3439 }
3440}
3441
3442trait Foo { fn foo(&self); }
3443
3444impl Foo for Bar {
3445 fn foo(&self) {
3446 self.func2();
3447 }
3448}
3449",
3450 )
3451 }
3452}