1 use hir::{
2 Adt, AsAssocItem, HasSource, HirDisplay, Module, PathResolution, Semantics, Type, TypeInfo,
3 };
4 use ide_db::{
5 base_db::FileId,
6 defs::{Definition, NameRefClass},
7 famous_defs::FamousDefs,
8 helpers::is_editable_crate,
9 path_transform::PathTransform,
10 FxHashMap, FxHashSet, RootDatabase, SnippetCap,
11 };
12 use stdx::to_lower_snake_case;
13 use syntax::{
14 ast::{
15 self,
16 edit::{AstNodeEdit, IndentLevel},
17 make, AstNode, CallExpr, HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds,
18 },
19 SyntaxKind, SyntaxNode, TextRange, TextSize,
20 };
21
22 use crate::{
23 utils::{convert_reference_type, find_struct_impl, render_snippet, Cursor},
24 AssistContext, AssistId, AssistKind, Assists,
25 };
26
27 // Assist: generate_function
28 //
29 // Adds a stub function with a signature matching the function under the cursor.
30 //
31 // ```
32 // struct Baz;
33 // fn baz() -> Baz { Baz }
34 // fn foo() {
35 // bar$0("", baz());
36 // }
37 //
38 // ```
39 // ->
40 // ```
41 // struct Baz;
42 // fn baz() -> Baz { Baz }
43 // fn foo() {
44 // bar("", baz());
45 // }
46 //
47 // fn bar(arg: &str, baz: Baz) ${0:-> _} {
48 // todo!()
49 // }
50 //
51 // ```
generate_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>52 pub(crate) fn generate_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
53 gen_fn(acc, ctx).or_else(|| gen_method(acc, ctx))
54 }
55
gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>56 fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
57 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
58 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
59 let path = path_expr.path()?;
60 let name_ref = path.segment()?.name_ref()?;
61 if ctx.sema.resolve_path(&path).is_some() {
62 // The function call already resolves, no need to add a function
63 return None;
64 }
65
66 let fn_name = &*name_ref.text();
67 let TargetInfo { target_module, adt_name, target, file, insert_offset } =
68 fn_target_info(ctx, path, &call, fn_name)?;
69
70 if let Some(m) = target_module {
71 if !is_editable_crate(m.krate(), ctx.db()) {
72 return None;
73 }
74 }
75
76 let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
77 let text_range = call.syntax().text_range();
78 let label = format!("Generate {} function", function_builder.fn_name);
79 add_func_to_accumulator(
80 acc,
81 ctx,
82 text_range,
83 function_builder,
84 insert_offset,
85 file,
86 adt_name,
87 label,
88 )
89 }
90
91 struct TargetInfo {
92 target_module: Option<Module>,
93 adt_name: Option<hir::Name>,
94 target: GeneratedFunctionTarget,
95 file: FileId,
96 insert_offset: TextSize,
97 }
98
99 impl TargetInfo {
new( target_module: Option<Module>, adt_name: Option<hir::Name>, target: GeneratedFunctionTarget, file: FileId, insert_offset: TextSize, ) -> Self100 fn new(
101 target_module: Option<Module>,
102 adt_name: Option<hir::Name>,
103 target: GeneratedFunctionTarget,
104 file: FileId,
105 insert_offset: TextSize,
106 ) -> Self {
107 Self { target_module, adt_name, target, file, insert_offset }
108 }
109 }
110
fn_target_info( ctx: &AssistContext<'_>, path: ast::Path, call: &CallExpr, fn_name: &str, ) -> Option<TargetInfo>111 fn fn_target_info(
112 ctx: &AssistContext<'_>,
113 path: ast::Path,
114 call: &CallExpr,
115 fn_name: &str,
116 ) -> Option<TargetInfo> {
117 match path.qualifier() {
118 Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
119 Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
120 get_fn_target_info(ctx, Some(module), call.clone())
121 }
122 Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
123 if let hir::Adt::Enum(_) = adt {
124 // Don't suggest generating function if the name starts with an uppercase letter
125 if fn_name.starts_with(char::is_uppercase) {
126 return None;
127 }
128 }
129
130 assoc_fn_target_info(ctx, call, adt, fn_name)
131 }
132 Some(hir::PathResolution::SelfType(impl_)) => {
133 let adt = impl_.self_ty(ctx.db()).as_adt()?;
134 assoc_fn_target_info(ctx, call, adt, fn_name)
135 }
136 _ => None,
137 },
138 _ => get_fn_target_info(ctx, None, call.clone()),
139 }
140 }
141
gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()>142 fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
143 let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
144 if ctx.sema.resolve_method_call(&call).is_some() {
145 return None;
146 }
147
148 let fn_name = call.name_ref()?;
149 let receiver_ty = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references();
150 let adt = receiver_ty.as_adt()?;
151
152 let target_module = adt.module(ctx.sema.db);
153 if !is_editable_crate(target_module.krate(), ctx.db()) {
154 return None;
155 }
156
157 let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
158 let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
159
160 let function_builder = FunctionBuilder::from_method_call(
161 ctx,
162 &call,
163 &fn_name,
164 receiver_ty,
165 target_module,
166 target,
167 )?;
168 let text_range = call.syntax().text_range();
169 let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
170 let label = format!("Generate {} method", function_builder.fn_name);
171 add_func_to_accumulator(
172 acc,
173 ctx,
174 text_range,
175 function_builder,
176 insert_offset,
177 file,
178 adt_name,
179 label,
180 )
181 }
182
add_func_to_accumulator( acc: &mut Assists, ctx: &AssistContext<'_>, text_range: TextRange, function_builder: FunctionBuilder, insert_offset: TextSize, file: FileId, adt_name: Option<hir::Name>, label: String, ) -> Option<()>183 fn add_func_to_accumulator(
184 acc: &mut Assists,
185 ctx: &AssistContext<'_>,
186 text_range: TextRange,
187 function_builder: FunctionBuilder,
188 insert_offset: TextSize,
189 file: FileId,
190 adt_name: Option<hir::Name>,
191 label: String,
192 ) -> Option<()> {
193 acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
194 let indent = IndentLevel::from_node(function_builder.target.syntax());
195 let function_template = function_builder.render(adt_name.is_some());
196 let mut func = function_template.to_string(ctx.config.snippet_cap);
197 if let Some(name) = adt_name {
198 // FIXME: adt may have generic params.
199 func = format!("\n{indent}impl {} {{\n{func}\n{indent}}}", name.display(ctx.db()));
200 }
201 builder.edit_file(file);
202 match ctx.config.snippet_cap {
203 Some(cap) => builder.insert_snippet(cap, insert_offset, func),
204 None => builder.insert(insert_offset, func),
205 }
206 })
207 }
208
get_adt_source( ctx: &AssistContext<'_>, adt: &hir::Adt, fn_name: &str, ) -> Option<(Option<ast::Impl>, FileId)>209 fn get_adt_source(
210 ctx: &AssistContext<'_>,
211 adt: &hir::Adt,
212 fn_name: &str,
213 ) -> Option<(Option<ast::Impl>, FileId)> {
214 let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
215 let file = ctx.sema.parse(range.file_id);
216 let adt_source =
217 ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
218 find_struct_impl(ctx, &adt_source, &[fn_name.to_string()]).map(|impl_| (impl_, range.file_id))
219 }
220
221 struct FunctionTemplate {
222 leading_ws: String,
223 fn_def: ast::Fn,
224 ret_type: Option<ast::RetType>,
225 should_focus_return_type: bool,
226 trailing_ws: String,
227 tail_expr: ast::Expr,
228 }
229
230 impl FunctionTemplate {
to_string(&self, cap: Option<SnippetCap>) -> String231 fn to_string(&self, cap: Option<SnippetCap>) -> String {
232 let Self { leading_ws, fn_def, ret_type, should_focus_return_type, trailing_ws, tail_expr } =
233 self;
234
235 let f = match cap {
236 Some(cap) => {
237 let cursor = if *should_focus_return_type {
238 // Focus the return type if there is one
239 match ret_type {
240 Some(ret_type) => ret_type.syntax(),
241 None => tail_expr.syntax(),
242 }
243 } else {
244 tail_expr.syntax()
245 };
246 render_snippet(cap, fn_def.syntax(), Cursor::Replace(cursor))
247 }
248 None => fn_def.to_string(),
249 };
250
251 format!("{leading_ws}{f}{trailing_ws}")
252 }
253 }
254
255 struct FunctionBuilder {
256 target: GeneratedFunctionTarget,
257 fn_name: ast::Name,
258 generic_param_list: Option<ast::GenericParamList>,
259 where_clause: Option<ast::WhereClause>,
260 params: ast::ParamList,
261 ret_type: Option<ast::RetType>,
262 should_focus_return_type: bool,
263 visibility: Visibility,
264 is_async: bool,
265 }
266
267 impl FunctionBuilder {
268 /// Prepares a generated function that matches `call`.
269 /// The function is generated in `target_module` or next to `call`
from_call( ctx: &AssistContext<'_>, call: &ast::CallExpr, fn_name: &str, target_module: Option<Module>, target: GeneratedFunctionTarget, ) -> Option<Self>270 fn from_call(
271 ctx: &AssistContext<'_>,
272 call: &ast::CallExpr,
273 fn_name: &str,
274 target_module: Option<Module>,
275 target: GeneratedFunctionTarget,
276 ) -> Option<Self> {
277 let target_module =
278 target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
279
280 let current_module = ctx.sema.scope(call.syntax())?.module();
281 let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
282 let fn_name = make::name(fn_name);
283 let mut necessary_generic_params = FxHashSet::default();
284 let params = fn_args(
285 ctx,
286 target_module,
287 ast::CallableExpr::Call(call.clone()),
288 &mut necessary_generic_params,
289 )?;
290
291 let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
292 let is_async = await_expr.is_some();
293
294 let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
295 let (ret_type, should_focus_return_type) =
296 make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params);
297
298 let (generic_param_list, where_clause) =
299 fn_generic_params(ctx, necessary_generic_params, &target)?;
300
301 Some(Self {
302 target,
303 fn_name,
304 generic_param_list,
305 where_clause,
306 params,
307 ret_type,
308 should_focus_return_type,
309 visibility,
310 is_async,
311 })
312 }
313
from_method_call( ctx: &AssistContext<'_>, call: &ast::MethodCallExpr, name: &ast::NameRef, receiver_ty: Type, target_module: Module, target: GeneratedFunctionTarget, ) -> Option<Self>314 fn from_method_call(
315 ctx: &AssistContext<'_>,
316 call: &ast::MethodCallExpr,
317 name: &ast::NameRef,
318 receiver_ty: Type,
319 target_module: Module,
320 target: GeneratedFunctionTarget,
321 ) -> Option<Self> {
322 let current_module = ctx.sema.scope(call.syntax())?.module();
323 let visibility = calculate_necessary_visibility(current_module, target_module, ctx);
324
325 let fn_name = make::name(&name.text());
326 let mut necessary_generic_params = FxHashSet::default();
327 necessary_generic_params.extend(receiver_ty.generic_params(ctx.db()));
328 let params = fn_args(
329 ctx,
330 target_module,
331 ast::CallableExpr::MethodCall(call.clone()),
332 &mut necessary_generic_params,
333 )?;
334
335 let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
336 let is_async = await_expr.is_some();
337
338 let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
339 let (ret_type, should_focus_return_type) =
340 make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params);
341
342 let (generic_param_list, where_clause) =
343 fn_generic_params(ctx, necessary_generic_params, &target)?;
344
345 Some(Self {
346 target,
347 fn_name,
348 generic_param_list,
349 where_clause,
350 params,
351 ret_type,
352 should_focus_return_type,
353 visibility,
354 is_async,
355 })
356 }
357
render(self, is_method: bool) -> FunctionTemplate358 fn render(self, is_method: bool) -> FunctionTemplate {
359 let placeholder_expr = make::ext::expr_todo();
360 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
361 let visibility = match self.visibility {
362 Visibility::None => None,
363 Visibility::Crate => Some(make::visibility_pub_crate()),
364 Visibility::Pub => Some(make::visibility_pub()),
365 };
366 let mut fn_def = make::fn_(
367 visibility,
368 self.fn_name,
369 self.generic_param_list,
370 self.where_clause,
371 self.params,
372 fn_body,
373 self.ret_type,
374 self.is_async,
375 false, // FIXME : const and unsafe are not handled yet.
376 false,
377 );
378 let leading_ws;
379 let trailing_ws;
380
381 match self.target {
382 GeneratedFunctionTarget::BehindItem(it) => {
383 let mut indent = IndentLevel::from_node(&it);
384 if is_method {
385 indent = indent + 1;
386 leading_ws = format!("{indent}");
387 } else {
388 leading_ws = format!("\n\n{indent}");
389 }
390
391 fn_def = fn_def.indent(indent);
392 trailing_ws = String::new();
393 }
394 GeneratedFunctionTarget::InEmptyItemList(it) => {
395 let indent = IndentLevel::from_node(&it);
396 let leading_indent = indent + 1;
397 leading_ws = format!("\n{leading_indent}");
398 fn_def = fn_def.indent(leading_indent);
399 trailing_ws = format!("\n{indent}");
400 }
401 };
402
403 FunctionTemplate {
404 leading_ws,
405 ret_type: fn_def.ret_type(),
406 // PANIC: we guarantee we always create a function body with a tail expr
407 tail_expr: fn_def.body().unwrap().tail_expr().unwrap(),
408 should_focus_return_type: self.should_focus_return_type,
409 fn_def,
410 trailing_ws,
411 }
412 }
413 }
414
415 /// Makes an optional return type along with whether the return type should be focused by the cursor.
416 /// If we cannot infer what the return type should be, we create a placeholder type.
417 ///
418 /// The rule for whether we focus a return type or not (and thus focus the function body),
419 /// is rather simple:
420 /// * If we could *not* infer what the return type should be, focus it (so the user can fill-in
421 /// the correct return type).
422 /// * If we could infer the return type, don't focus it (and thus focus the function body) so the
423 /// user can change the `todo!` function body.
make_return_type( ctx: &AssistContext<'_>, expr: &ast::Expr, target_module: Module, necessary_generic_params: &mut FxHashSet<hir::GenericParam>, ) -> (Option<ast::RetType>, bool)424 fn make_return_type(
425 ctx: &AssistContext<'_>,
426 expr: &ast::Expr,
427 target_module: Module,
428 necessary_generic_params: &mut FxHashSet<hir::GenericParam>,
429 ) -> (Option<ast::RetType>, bool) {
430 let (ret_ty, should_focus_return_type) = {
431 match ctx.sema.type_of_expr(expr).map(TypeInfo::original) {
432 Some(ty) if ty.is_unknown() => (Some(make::ty_placeholder()), true),
433 None => (Some(make::ty_placeholder()), true),
434 Some(ty) if ty.is_unit() => (None, false),
435 Some(ty) => {
436 necessary_generic_params.extend(ty.generic_params(ctx.db()));
437 let rendered = ty.display_source_code(ctx.db(), target_module.into(), true);
438 match rendered {
439 Ok(rendered) => (Some(make::ty(&rendered)), false),
440 Err(_) => (Some(make::ty_placeholder()), true),
441 }
442 }
443 }
444 };
445 let ret_type = ret_ty.map(make::ret_type);
446 (ret_type, should_focus_return_type)
447 }
448
get_fn_target_info( ctx: &AssistContext<'_>, target_module: Option<Module>, call: CallExpr, ) -> Option<TargetInfo>449 fn get_fn_target_info(
450 ctx: &AssistContext<'_>,
451 target_module: Option<Module>,
452 call: CallExpr,
453 ) -> Option<TargetInfo> {
454 let (target, file, insert_offset) = get_fn_target(ctx, target_module, call)?;
455 Some(TargetInfo::new(target_module, None, target, file, insert_offset))
456 }
457
get_fn_target( ctx: &AssistContext<'_>, target_module: Option<Module>, call: CallExpr, ) -> Option<(GeneratedFunctionTarget, FileId, TextSize)>458 fn get_fn_target(
459 ctx: &AssistContext<'_>,
460 target_module: Option<Module>,
461 call: CallExpr,
462 ) -> Option<(GeneratedFunctionTarget, FileId, TextSize)> {
463 let mut file = ctx.file_id();
464 let target = match target_module {
465 Some(target_module) => {
466 let module_source = target_module.definition_source(ctx.db());
467 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
468 file = in_file;
469 target
470 }
471 None => next_space_for_fn_after_call_site(ast::CallableExpr::Call(call))?,
472 };
473 Some((target.clone(), file, get_insert_offset(&target)))
474 }
475
get_method_target( ctx: &AssistContext<'_>, impl_: &Option<ast::Impl>, adt: &Adt, ) -> Option<(GeneratedFunctionTarget, TextSize)>476 fn get_method_target(
477 ctx: &AssistContext<'_>,
478 impl_: &Option<ast::Impl>,
479 adt: &Adt,
480 ) -> Option<(GeneratedFunctionTarget, TextSize)> {
481 let target = match impl_ {
482 Some(impl_) => next_space_for_fn_in_impl(impl_)?,
483 None => {
484 GeneratedFunctionTarget::BehindItem(adt.source(ctx.sema.db)?.syntax().value.clone())
485 }
486 };
487 Some((target.clone(), get_insert_offset(&target)))
488 }
489
assoc_fn_target_info( ctx: &AssistContext<'_>, call: &CallExpr, adt: hir::Adt, fn_name: &str, ) -> Option<TargetInfo>490 fn assoc_fn_target_info(
491 ctx: &AssistContext<'_>,
492 call: &CallExpr,
493 adt: hir::Adt,
494 fn_name: &str,
495 ) -> Option<TargetInfo> {
496 let current_module = ctx.sema.scope(call.syntax())?.module();
497 let module = adt.module(ctx.sema.db);
498 let target_module = if current_module == module { None } else { Some(module) };
499 if current_module.krate() != module.krate() {
500 return None;
501 }
502 let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
503 let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
504 let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
505 Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset))
506 }
507
get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize508 fn get_insert_offset(target: &GeneratedFunctionTarget) -> TextSize {
509 match &target {
510 GeneratedFunctionTarget::BehindItem(it) => it.text_range().end(),
511 GeneratedFunctionTarget::InEmptyItemList(it) => it.text_range().start() + TextSize::of('{'),
512 }
513 }
514
515 #[derive(Clone)]
516 enum GeneratedFunctionTarget {
517 BehindItem(SyntaxNode),
518 InEmptyItemList(SyntaxNode),
519 }
520
521 impl GeneratedFunctionTarget {
syntax(&self) -> &SyntaxNode522 fn syntax(&self) -> &SyntaxNode {
523 match self {
524 GeneratedFunctionTarget::BehindItem(it) => it,
525 GeneratedFunctionTarget::InEmptyItemList(it) => it,
526 }
527 }
528
parent(&self) -> SyntaxNode529 fn parent(&self) -> SyntaxNode {
530 match self {
531 GeneratedFunctionTarget::BehindItem(it) => it.parent().expect("item without parent"),
532 GeneratedFunctionTarget::InEmptyItemList(it) => it.clone(),
533 }
534 }
535 }
536
537 /// Computes parameter list for the generated function.
fn_args( ctx: &AssistContext<'_>, target_module: Module, call: ast::CallableExpr, necessary_generic_params: &mut FxHashSet<hir::GenericParam>, ) -> Option<ast::ParamList>538 fn fn_args(
539 ctx: &AssistContext<'_>,
540 target_module: Module,
541 call: ast::CallableExpr,
542 necessary_generic_params: &mut FxHashSet<hir::GenericParam>,
543 ) -> Option<ast::ParamList> {
544 let mut arg_names = Vec::new();
545 let mut arg_types = Vec::new();
546 for arg in call.arg_list()?.args() {
547 arg_names.push(fn_arg_name(&ctx.sema, &arg));
548 arg_types.push(fn_arg_type(ctx, target_module, &arg, necessary_generic_params));
549 }
550 deduplicate_arg_names(&mut arg_names);
551 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| {
552 make::param(make::ext::simple_ident_pat(make::name(&name)).into(), make::ty(&ty))
553 });
554
555 Some(make::param_list(
556 match call {
557 ast::CallableExpr::Call(_) => None,
558 ast::CallableExpr::MethodCall(_) => Some(make::self_param()),
559 },
560 params,
561 ))
562 }
563
564 /// Gets parameter bounds and where predicates in scope and filters out irrelevant ones. Returns
565 /// `None` when it fails to get scope information.
566 ///
567 /// See comment on `filter_unnecessary_bounds()` for what bounds we consider relevant.
568 ///
569 /// NOTE: Generic parameters returned from this function may cause name clash at `target`. We don't
570 /// currently do anything about it because it's actually easy to resolve it after the assist: just
571 /// use the Rename functionality.
fn_generic_params( ctx: &AssistContext<'_>, necessary_params: FxHashSet<hir::GenericParam>, target: &GeneratedFunctionTarget, ) -> Option<(Option<ast::GenericParamList>, Option<ast::WhereClause>)>572 fn fn_generic_params(
573 ctx: &AssistContext<'_>,
574 necessary_params: FxHashSet<hir::GenericParam>,
575 target: &GeneratedFunctionTarget,
576 ) -> Option<(Option<ast::GenericParamList>, Option<ast::WhereClause>)> {
577 if necessary_params.is_empty() {
578 // Not really needed but fast path.
579 return Some((None, None));
580 }
581
582 // 1. Get generic parameters (with bounds) and where predicates in scope.
583 let (generic_params, where_preds) = params_and_where_preds_in_scope(ctx);
584
585 // 2. Extract type parameters included in each bound.
586 let mut generic_params = generic_params
587 .into_iter()
588 .filter_map(|it| compute_contained_params_in_generic_param(ctx, it))
589 .collect();
590 let mut where_preds = where_preds
591 .into_iter()
592 .filter_map(|it| compute_contained_params_in_where_pred(ctx, it))
593 .collect();
594
595 // 3. Filter out unnecessary bounds.
596 filter_unnecessary_bounds(&mut generic_params, &mut where_preds, necessary_params);
597 filter_bounds_in_scope(&mut generic_params, &mut where_preds, ctx, target);
598
599 let generic_params: Vec<_> =
600 generic_params.into_iter().map(|it| it.node.clone_for_update()).collect();
601 let where_preds: Vec<_> =
602 where_preds.into_iter().map(|it| it.node.clone_for_update()).collect();
603
604 // 4. Rewrite paths
605 if let Some(param) = generic_params.first() {
606 let source_scope = ctx.sema.scope(param.syntax())?;
607 let target_scope = ctx.sema.scope(&target.parent())?;
608 if source_scope.module() != target_scope.module() {
609 let transform = PathTransform::generic_transformation(&target_scope, &source_scope);
610 let generic_params = generic_params.iter().map(|it| it.syntax());
611 let where_preds = where_preds.iter().map(|it| it.syntax());
612 transform.apply_all(generic_params.chain(where_preds));
613 }
614 }
615
616 let generic_param_list = make::generic_param_list(generic_params);
617 let where_clause =
618 if where_preds.is_empty() { None } else { Some(make::where_clause(where_preds)) };
619
620 Some((Some(generic_param_list), where_clause))
621 }
622
params_and_where_preds_in_scope( ctx: &AssistContext<'_>, ) -> (Vec<ast::GenericParam>, Vec<ast::WherePred>)623 fn params_and_where_preds_in_scope(
624 ctx: &AssistContext<'_>,
625 ) -> (Vec<ast::GenericParam>, Vec<ast::WherePred>) {
626 let Some(body) = containing_body(ctx) else { return Default::default(); };
627
628 let mut generic_params = Vec::new();
629 let mut where_clauses = Vec::new();
630
631 // There are two items where generic parameters currently in scope may be declared: the item
632 // the cursor is at, and its parent (if any).
633 //
634 // We handle parent first so that their generic parameters appear first in the generic
635 // parameter list of the function we're generating.
636 let db = ctx.db();
637 if let Some(parent) = body.as_assoc_item(db).map(|it| it.container(db)) {
638 match parent {
639 hir::AssocItemContainer::Impl(it) => {
640 let (params, clauses) = get_bounds_in_scope(ctx, it);
641 generic_params.extend(params);
642 where_clauses.extend(clauses);
643 }
644 hir::AssocItemContainer::Trait(it) => {
645 let (params, clauses) = get_bounds_in_scope(ctx, it);
646 generic_params.extend(params);
647 where_clauses.extend(clauses);
648 }
649 }
650 }
651
652 // Other defs with body may inherit generic parameters from its parent, but never have their
653 // own generic parameters.
654 if let hir::DefWithBody::Function(it) = body {
655 let (params, clauses) = get_bounds_in_scope(ctx, it);
656 generic_params.extend(params);
657 where_clauses.extend(clauses);
658 }
659
660 (generic_params, where_clauses)
661 }
662
containing_body(ctx: &AssistContext<'_>) -> Option<hir::DefWithBody>663 fn containing_body(ctx: &AssistContext<'_>) -> Option<hir::DefWithBody> {
664 let item: ast::Item = ctx.find_node_at_offset()?;
665 let def = match item {
666 ast::Item::Fn(it) => ctx.sema.to_def(&it)?.into(),
667 ast::Item::Const(it) => ctx.sema.to_def(&it)?.into(),
668 ast::Item::Static(it) => ctx.sema.to_def(&it)?.into(),
669 _ => return None,
670 };
671 Some(def)
672 }
673
get_bounds_in_scope<D>( ctx: &AssistContext<'_>, def: D, ) -> (impl Iterator<Item = ast::GenericParam>, impl Iterator<Item = ast::WherePred>) where D: HasSource, D::Ast: HasGenericParams,674 fn get_bounds_in_scope<D>(
675 ctx: &AssistContext<'_>,
676 def: D,
677 ) -> (impl Iterator<Item = ast::GenericParam>, impl Iterator<Item = ast::WherePred>)
678 where
679 D: HasSource,
680 D::Ast: HasGenericParams,
681 {
682 // This function should be only called with `Impl`, `Trait`, or `Function`, for which it's
683 // infallible to get source ast.
684 let node = ctx.sema.source(def).unwrap().value;
685 let generic_params = node.generic_param_list().into_iter().flat_map(|it| it.generic_params());
686 let where_clauses = node.where_clause().into_iter().flat_map(|it| it.predicates());
687 (generic_params, where_clauses)
688 }
689
690 #[derive(Debug)]
691 struct ParamBoundWithParams {
692 node: ast::GenericParam,
693 /// Generic parameter `node` introduces.
694 ///
695 /// ```text
696 /// impl<T> S<T> {
697 /// fn f<U: Trait<T>>() {}
698 /// ^ this
699 /// }
700 /// ```
701 ///
702 /// `U` in this example.
703 self_ty_param: hir::GenericParam,
704 /// Generic parameters contained in the trait reference of this bound.
705 ///
706 /// ```text
707 /// impl<T> S<T> {
708 /// fn f<U: Trait<T>>() {}
709 /// ^^^^^^^^ params in this part
710 /// }
711 /// ```
712 ///
713 /// `T` in this example.
714 other_params: FxHashSet<hir::GenericParam>,
715 }
716
717 #[derive(Debug)]
718 struct WherePredWithParams {
719 node: ast::WherePred,
720 /// Generic parameters contained in the "self type" of this where predicate.
721 ///
722 /// ```text
723 /// Struct<T, U>: Trait<T, Assoc = V>,
724 /// ^^^^^^^^^^^^ params in this part
725 /// ```
726 ///
727 /// `T` and `U` in this example.
728 self_ty_params: FxHashSet<hir::GenericParam>,
729 /// Generic parameters contained in the trait reference of this where predicate.
730 ///
731 /// ```text
732 /// Struct<T, U>: Trait<T, Assoc = V>,
733 /// ^^^^^^^^^^^^^^^^^^^ params in this part
734 /// ```
735 ///
736 /// `T` and `V` in this example.
737 other_params: FxHashSet<hir::GenericParam>,
738 }
739
compute_contained_params_in_generic_param( ctx: &AssistContext<'_>, node: ast::GenericParam, ) -> Option<ParamBoundWithParams>740 fn compute_contained_params_in_generic_param(
741 ctx: &AssistContext<'_>,
742 node: ast::GenericParam,
743 ) -> Option<ParamBoundWithParams> {
744 match &node {
745 ast::GenericParam::TypeParam(ty) => {
746 let self_ty_param = ctx.sema.to_def(ty)?.into();
747
748 let other_params = ty
749 .type_bound_list()
750 .into_iter()
751 .flat_map(|it| it.bounds())
752 .flat_map(|bound| bound.syntax().descendants())
753 .filter_map(|node| filter_generic_params(ctx, node))
754 .collect();
755
756 Some(ParamBoundWithParams { node, self_ty_param, other_params })
757 }
758 ast::GenericParam::ConstParam(ct) => {
759 let self_ty_param = ctx.sema.to_def(ct)?.into();
760 Some(ParamBoundWithParams { node, self_ty_param, other_params: FxHashSet::default() })
761 }
762 ast::GenericParam::LifetimeParam(_) => {
763 // FIXME: It might be a good idea to handle lifetime parameters too.
764 None
765 }
766 }
767 }
768
compute_contained_params_in_where_pred( ctx: &AssistContext<'_>, node: ast::WherePred, ) -> Option<WherePredWithParams>769 fn compute_contained_params_in_where_pred(
770 ctx: &AssistContext<'_>,
771 node: ast::WherePred,
772 ) -> Option<WherePredWithParams> {
773 let self_ty = node.ty()?;
774 let bound_list = node.type_bound_list()?;
775
776 let self_ty_params = self_ty
777 .syntax()
778 .descendants()
779 .filter_map(|node| filter_generic_params(ctx, node))
780 .collect();
781
782 let other_params = bound_list
783 .bounds()
784 .flat_map(|bound| bound.syntax().descendants())
785 .filter_map(|node| filter_generic_params(ctx, node))
786 .collect();
787
788 Some(WherePredWithParams { node, self_ty_params, other_params })
789 }
790
filter_generic_params(ctx: &AssistContext<'_>, node: SyntaxNode) -> Option<hir::GenericParam>791 fn filter_generic_params(ctx: &AssistContext<'_>, node: SyntaxNode) -> Option<hir::GenericParam> {
792 let path = ast::Path::cast(node)?;
793 match ctx.sema.resolve_path(&path)? {
794 PathResolution::TypeParam(it) => Some(it.into()),
795 PathResolution::ConstParam(it) => Some(it.into()),
796 _ => None,
797 }
798 }
799
800 /// Filters out irrelevant bounds from `generic_params` and `where_preds`.
801 ///
802 /// Say we have a trait bound `Struct<T>: Trait<U>`. Given `necessary_params`, when is it relevant
803 /// and when not? Some observations:
804 /// - When `necessary_params` contains `T`, it's likely that we want this bound, but now we have
805 /// an extra param to consider: `U`.
806 /// - On the other hand, when `necessary_params` contains `U` (but not `T`), then it's unlikely
807 /// that we want this bound because it doesn't really constrain `U`.
808 ///
809 /// (FIXME?: The latter clause might be overstating. We may want to include the bound if the self
810 /// type does *not* include generic params at all - like `Option<i32>: From<U>`)
811 ///
812 /// Can we make this a bit more formal? Let's define "dependency" between generic parameters and
813 /// trait bounds:
814 /// - A generic parameter `T` depends on a trait bound if `T` appears in the self type (i.e. left
815 /// part) of the bound.
816 /// - A trait bound depends on a generic parameter `T` if `T` appears in the bound.
817 ///
818 /// Using the notion, what we want is all the bounds that params in `necessary_params`
819 /// *transitively* depend on!
820 ///
821 /// Now it's not hard to solve: we build a dependency graph and compute all reachable nodes from
822 /// nodes that represent params in `necessary_params` by usual and boring DFS.
823 ///
824 /// The time complexity is O(|generic_params| + |where_preds| + |necessary_params|).
filter_unnecessary_bounds( generic_params: &mut Vec<ParamBoundWithParams>, where_preds: &mut Vec<WherePredWithParams>, necessary_params: FxHashSet<hir::GenericParam>, )825 fn filter_unnecessary_bounds(
826 generic_params: &mut Vec<ParamBoundWithParams>,
827 where_preds: &mut Vec<WherePredWithParams>,
828 necessary_params: FxHashSet<hir::GenericParam>,
829 ) {
830 // All `self_ty_param` should be unique as they were collected from `ast::GenericParamList`s.
831 let param_map: FxHashMap<hir::GenericParam, usize> =
832 generic_params.iter().map(|it| it.self_ty_param).zip(0..).collect();
833 let param_count = param_map.len();
834 let generic_params_upper_bound = param_count + generic_params.len();
835 let node_count = generic_params_upper_bound + where_preds.len();
836
837 // | node index range | what the node represents |
838 // |-----------------------------------------|--------------------------|
839 // | 0..param_count | generic parameter |
840 // | param_count..generic_params_upper_bound | `ast::GenericParam` |
841 // | generic_params_upper_bound..node_count | `ast::WherePred` |
842 let mut graph = Graph::new(node_count);
843 for (pred, pred_idx) in generic_params.iter().zip(param_count..) {
844 let param_idx = param_map[&pred.self_ty_param];
845 graph.add_edge(param_idx, pred_idx);
846 graph.add_edge(pred_idx, param_idx);
847
848 for param in &pred.other_params {
849 let param_idx = param_map[param];
850 graph.add_edge(pred_idx, param_idx);
851 }
852 }
853 for (pred, pred_idx) in where_preds.iter().zip(generic_params_upper_bound..) {
854 for param in &pred.self_ty_params {
855 let param_idx = param_map[param];
856 graph.add_edge(param_idx, pred_idx);
857 graph.add_edge(pred_idx, param_idx);
858 }
859 for param in &pred.other_params {
860 let param_idx = param_map[param];
861 graph.add_edge(pred_idx, param_idx);
862 }
863 }
864
865 let starting_nodes = necessary_params.iter().map(|param| param_map[param]);
866 let reachable = graph.compute_reachable_nodes(starting_nodes);
867
868 // Not pretty, but effective. If only there were `Vec::retain_index()`...
869 let mut idx = param_count;
870 generic_params.retain(|_| {
871 idx += 1;
872 reachable[idx - 1]
873 });
874 stdx::always!(idx == generic_params_upper_bound, "inconsistent index");
875 where_preds.retain(|_| {
876 idx += 1;
877 reachable[idx - 1]
878 });
879 }
880
881 /// Filters out bounds from impl if we're generating the function into the same impl we're
882 /// generating from.
filter_bounds_in_scope( generic_params: &mut Vec<ParamBoundWithParams>, where_preds: &mut Vec<WherePredWithParams>, ctx: &AssistContext<'_>, target: &GeneratedFunctionTarget, ) -> Option<()>883 fn filter_bounds_in_scope(
884 generic_params: &mut Vec<ParamBoundWithParams>,
885 where_preds: &mut Vec<WherePredWithParams>,
886 ctx: &AssistContext<'_>,
887 target: &GeneratedFunctionTarget,
888 ) -> Option<()> {
889 let target_impl = target.parent().ancestors().find_map(ast::Impl::cast)?;
890 let target_impl = ctx.sema.to_def(&target_impl)?;
891 // It's sufficient to test only the first element of `generic_params` because of the order of
892 // insertion (see `params_and_where_preds_in_scope()`).
893 let def = generic_params.first()?.self_ty_param.parent();
894 if def != hir::GenericDef::Impl(target_impl) {
895 return None;
896 }
897
898 // Now we know every element that belongs to an impl would be in scope at `target`, we can
899 // filter them out just by looking at their parent.
900 generic_params.retain(|it| !matches!(it.self_ty_param.parent(), hir::GenericDef::Impl(_)));
901 where_preds.retain(|it| {
902 it.node.syntax().parent().and_then(|it| it.parent()).and_then(ast::Impl::cast).is_none()
903 });
904
905 Some(())
906 }
907
908 /// Makes duplicate argument names unique by appending incrementing numbers.
909 ///
910 /// ```
911 /// let mut names: Vec<String> =
912 /// vec!["foo".into(), "foo".into(), "bar".into(), "baz".into(), "bar".into()];
913 /// deduplicate_arg_names(&mut names);
914 /// let expected: Vec<String> =
915 /// vec!["foo_1".into(), "foo_2".into(), "bar_1".into(), "baz".into(), "bar_2".into()];
916 /// assert_eq!(names, expected);
917 /// ```
deduplicate_arg_names(arg_names: &mut [String])918 fn deduplicate_arg_names(arg_names: &mut [String]) {
919 let mut arg_name_counts = FxHashMap::default();
920 for name in arg_names.iter() {
921 *arg_name_counts.entry(name).or_insert(0) += 1;
922 }
923 let duplicate_arg_names: FxHashSet<String> = arg_name_counts
924 .into_iter()
925 .filter(|(_, count)| *count >= 2)
926 .map(|(name, _)| name.clone())
927 .collect();
928
929 let mut counter_per_name = FxHashMap::default();
930 for arg_name in arg_names.iter_mut() {
931 if duplicate_arg_names.contains(arg_name) {
932 let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
933 arg_name.push('_');
934 arg_name.push_str(&counter.to_string());
935 *counter += 1;
936 }
937 }
938 }
939
fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> String940 fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> String {
941 let name = (|| match arg_expr {
942 ast::Expr::CastExpr(cast_expr) => Some(fn_arg_name(sema, &cast_expr.expr()?)),
943 expr => {
944 let name_ref = expr
945 .syntax()
946 .descendants()
947 .filter_map(ast::NameRef::cast)
948 .filter(|name| name.ident_token().is_some())
949 .last()?;
950 if let Some(NameRefClass::Definition(Definition::Const(_) | Definition::Static(_))) =
951 NameRefClass::classify(sema, &name_ref)
952 {
953 return Some(name_ref.to_string().to_lowercase());
954 };
955 Some(to_lower_snake_case(&name_ref.to_string()))
956 }
957 })();
958 match name {
959 Some(mut name) if name.starts_with(|c: char| c.is_ascii_digit()) => {
960 name.insert_str(0, "arg");
961 name
962 }
963 Some(name) => name,
964 None => "arg".to_string(),
965 }
966 }
967
fn_arg_type( ctx: &AssistContext<'_>, target_module: Module, fn_arg: &ast::Expr, generic_params: &mut FxHashSet<hir::GenericParam>, ) -> String968 fn fn_arg_type(
969 ctx: &AssistContext<'_>,
970 target_module: Module,
971 fn_arg: &ast::Expr,
972 generic_params: &mut FxHashSet<hir::GenericParam>,
973 ) -> String {
974 fn maybe_displayed_type(
975 ctx: &AssistContext<'_>,
976 target_module: Module,
977 fn_arg: &ast::Expr,
978 generic_params: &mut FxHashSet<hir::GenericParam>,
979 ) -> Option<String> {
980 let ty = ctx.sema.type_of_expr(fn_arg)?.adjusted();
981 if ty.is_unknown() {
982 return None;
983 }
984
985 generic_params.extend(ty.generic_params(ctx.db()));
986
987 if ty.is_reference() || ty.is_mutable_reference() {
988 let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
989 convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
990 .map(|conversion| conversion.convert_type(ctx.db()))
991 .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
992 } else {
993 ty.display_source_code(ctx.db(), target_module.into(), true).ok()
994 }
995 }
996
997 maybe_displayed_type(ctx, target_module, fn_arg, generic_params)
998 .unwrap_or_else(|| String::from("_"))
999 }
1000
1001 /// Returns the position inside the current mod or file
1002 /// directly after the current block
1003 /// We want to write the generated function directly after
1004 /// fns, impls or macro calls, but inside mods
next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<GeneratedFunctionTarget>1005 fn next_space_for_fn_after_call_site(expr: ast::CallableExpr) -> Option<GeneratedFunctionTarget> {
1006 let mut ancestors = expr.syntax().ancestors().peekable();
1007 let mut last_ancestor: Option<SyntaxNode> = None;
1008 while let Some(next_ancestor) = ancestors.next() {
1009 match next_ancestor.kind() {
1010 SyntaxKind::SOURCE_FILE => {
1011 break;
1012 }
1013 SyntaxKind::ITEM_LIST => {
1014 if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) {
1015 break;
1016 }
1017 }
1018 _ => {}
1019 }
1020 last_ancestor = Some(next_ancestor);
1021 }
1022 last_ancestor.map(GeneratedFunctionTarget::BehindItem)
1023 }
1024
next_space_for_fn_in_module( db: &dyn hir::db::ExpandDatabase, module_source: &hir::InFile<hir::ModuleSource>, ) -> Option<(FileId, GeneratedFunctionTarget)>1025 fn next_space_for_fn_in_module(
1026 db: &dyn hir::db::ExpandDatabase,
1027 module_source: &hir::InFile<hir::ModuleSource>,
1028 ) -> Option<(FileId, GeneratedFunctionTarget)> {
1029 let file = module_source.file_id.original_file(db);
1030 let assist_item = match &module_source.value {
1031 hir::ModuleSource::SourceFile(it) => match it.items().last() {
1032 Some(last_item) => GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()),
1033 None => GeneratedFunctionTarget::BehindItem(it.syntax().clone()),
1034 },
1035 hir::ModuleSource::Module(it) => match it.item_list().and_then(|it| it.items().last()) {
1036 Some(last_item) => GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()),
1037 None => GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone()),
1038 },
1039 hir::ModuleSource::BlockExpr(it) => {
1040 if let Some(last_item) =
1041 it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
1042 {
1043 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
1044 } else {
1045 GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
1046 }
1047 }
1048 };
1049 Some((file, assist_item))
1050 }
1051
next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarget>1052 fn next_space_for_fn_in_impl(impl_: &ast::Impl) -> Option<GeneratedFunctionTarget> {
1053 let assoc_item_list = impl_.assoc_item_list()?;
1054 if let Some(last_item) = assoc_item_list.assoc_items().last() {
1055 Some(GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()))
1056 } else {
1057 Some(GeneratedFunctionTarget::InEmptyItemList(assoc_item_list.syntax().clone()))
1058 }
1059 }
1060
1061 #[derive(Clone, Copy)]
1062 enum Visibility {
1063 None,
1064 Crate,
1065 Pub,
1066 }
1067
calculate_necessary_visibility( current_module: Module, target_module: Module, ctx: &AssistContext<'_>, ) -> Visibility1068 fn calculate_necessary_visibility(
1069 current_module: Module,
1070 target_module: Module,
1071 ctx: &AssistContext<'_>,
1072 ) -> Visibility {
1073 let db = ctx.db();
1074 let current_module = current_module.nearest_non_block_module(db);
1075 let target_module = target_module.nearest_non_block_module(db);
1076
1077 if target_module.krate() != current_module.krate() {
1078 Visibility::Pub
1079 } else if current_module.path_to_root(db).contains(&target_module) {
1080 Visibility::None
1081 } else {
1082 Visibility::Crate
1083 }
1084 }
1085
1086 // This is never intended to be used as a generic graph structure. If there's ever another need of
1087 // graph algorithm, consider adding a library for that (and replace the following).
1088 /// Minimally implemented directed graph structure represented by adjacency list.
1089 struct Graph {
1090 edges: Vec<Vec<usize>>,
1091 }
1092
1093 impl Graph {
new(node_count: usize) -> Self1094 fn new(node_count: usize) -> Self {
1095 Self { edges: vec![Vec::new(); node_count] }
1096 }
1097
add_edge(&mut self, from: usize, to: usize)1098 fn add_edge(&mut self, from: usize, to: usize) {
1099 self.edges[from].push(to);
1100 }
1101
edges_for(&self, node_idx: usize) -> &[usize]1102 fn edges_for(&self, node_idx: usize) -> &[usize] {
1103 &self.edges[node_idx]
1104 }
1105
len(&self) -> usize1106 fn len(&self) -> usize {
1107 self.edges.len()
1108 }
1109
compute_reachable_nodes( &self, starting_nodes: impl IntoIterator<Item = usize>, ) -> Vec<bool>1110 fn compute_reachable_nodes(
1111 &self,
1112 starting_nodes: impl IntoIterator<Item = usize>,
1113 ) -> Vec<bool> {
1114 let mut visitor = Visitor::new(self);
1115 for idx in starting_nodes {
1116 visitor.mark_reachable(idx);
1117 }
1118 visitor.visited
1119 }
1120 }
1121
1122 struct Visitor<'g> {
1123 graph: &'g Graph,
1124 visited: Vec<bool>,
1125 // Stack is held in this struct so we can reuse its buffer.
1126 stack: Vec<usize>,
1127 }
1128
1129 impl<'g> Visitor<'g> {
new(graph: &'g Graph) -> Self1130 fn new(graph: &'g Graph) -> Self {
1131 let visited = vec![false; graph.len()];
1132 Self { graph, visited, stack: Vec::new() }
1133 }
1134
mark_reachable(&mut self, start_idx: usize)1135 fn mark_reachable(&mut self, start_idx: usize) {
1136 // non-recursive DFS
1137 stdx::always!(self.stack.is_empty());
1138
1139 self.stack.push(start_idx);
1140 while let Some(idx) = self.stack.pop() {
1141 if !self.visited[idx] {
1142 self.visited[idx] = true;
1143 for &neighbor in self.graph.edges_for(idx) {
1144 if !self.visited[neighbor] {
1145 self.stack.push(neighbor);
1146 }
1147 }
1148 }
1149 }
1150 }
1151 }
1152
1153 #[cfg(test)]
1154 mod tests {
1155 use crate::tests::{check_assist, check_assist_not_applicable};
1156
1157 use super::*;
1158
1159 #[test]
add_function_with_no_args()1160 fn add_function_with_no_args() {
1161 check_assist(
1162 generate_function,
1163 r"
1164 fn foo() {
1165 bar$0();
1166 }
1167 ",
1168 r"
1169 fn foo() {
1170 bar();
1171 }
1172
1173 fn bar() ${0:-> _} {
1174 todo!()
1175 }
1176 ",
1177 )
1178 }
1179
1180 #[test]
add_function_from_method()1181 fn add_function_from_method() {
1182 // This ensures that the function is correctly generated
1183 // in the next outer mod or file
1184 check_assist(
1185 generate_function,
1186 r"
1187 impl Foo {
1188 fn foo() {
1189 bar$0();
1190 }
1191 }
1192 ",
1193 r"
1194 impl Foo {
1195 fn foo() {
1196 bar();
1197 }
1198 }
1199
1200 fn bar() ${0:-> _} {
1201 todo!()
1202 }
1203 ",
1204 )
1205 }
1206
1207 #[test]
add_function_directly_after_current_block()1208 fn add_function_directly_after_current_block() {
1209 // The new fn should not be created at the end of the file or module
1210 check_assist(
1211 generate_function,
1212 r"
1213 fn foo1() {
1214 bar$0();
1215 }
1216
1217 fn foo2() {}
1218 ",
1219 r"
1220 fn foo1() {
1221 bar();
1222 }
1223
1224 fn bar() ${0:-> _} {
1225 todo!()
1226 }
1227
1228 fn foo2() {}
1229 ",
1230 )
1231 }
1232
1233 #[test]
add_function_with_no_args_in_same_module()1234 fn add_function_with_no_args_in_same_module() {
1235 check_assist(
1236 generate_function,
1237 r"
1238 mod baz {
1239 fn foo() {
1240 bar$0();
1241 }
1242 }
1243 ",
1244 r"
1245 mod baz {
1246 fn foo() {
1247 bar();
1248 }
1249
1250 fn bar() ${0:-> _} {
1251 todo!()
1252 }
1253 }
1254 ",
1255 )
1256 }
1257
1258 #[test]
add_function_with_upper_camel_case_arg()1259 fn add_function_with_upper_camel_case_arg() {
1260 check_assist(
1261 generate_function,
1262 r"
1263 struct BazBaz;
1264 fn foo() {
1265 bar$0(BazBaz);
1266 }
1267 ",
1268 r"
1269 struct BazBaz;
1270 fn foo() {
1271 bar(BazBaz);
1272 }
1273
1274 fn bar(baz_baz: BazBaz) ${0:-> _} {
1275 todo!()
1276 }
1277 ",
1278 );
1279 }
1280
1281 #[test]
add_function_with_upper_camel_case_arg_as_cast()1282 fn add_function_with_upper_camel_case_arg_as_cast() {
1283 check_assist(
1284 generate_function,
1285 r"
1286 struct BazBaz;
1287 fn foo() {
1288 bar$0(&BazBaz as *const BazBaz);
1289 }
1290 ",
1291 r"
1292 struct BazBaz;
1293 fn foo() {
1294 bar(&BazBaz as *const BazBaz);
1295 }
1296
1297 fn bar(baz_baz: *const BazBaz) ${0:-> _} {
1298 todo!()
1299 }
1300 ",
1301 );
1302 }
1303
1304 #[test]
add_function_with_function_call_arg()1305 fn add_function_with_function_call_arg() {
1306 check_assist(
1307 generate_function,
1308 r"
1309 struct Baz;
1310 fn baz() -> Baz { todo!() }
1311 fn foo() {
1312 bar$0(baz());
1313 }
1314 ",
1315 r"
1316 struct Baz;
1317 fn baz() -> Baz { todo!() }
1318 fn foo() {
1319 bar(baz());
1320 }
1321
1322 fn bar(baz: Baz) ${0:-> _} {
1323 todo!()
1324 }
1325 ",
1326 );
1327 }
1328
1329 #[test]
add_function_with_method_call_arg()1330 fn add_function_with_method_call_arg() {
1331 check_assist(
1332 generate_function,
1333 r"
1334 struct Baz;
1335 impl Baz {
1336 fn foo(&self) -> Baz {
1337 ba$0r(self.baz())
1338 }
1339 fn baz(&self) -> Baz {
1340 Baz
1341 }
1342 }
1343 ",
1344 r"
1345 struct Baz;
1346 impl Baz {
1347 fn foo(&self) -> Baz {
1348 bar(self.baz())
1349 }
1350 fn baz(&self) -> Baz {
1351 Baz
1352 }
1353 }
1354
1355 fn bar(baz: Baz) -> Baz {
1356 ${0:todo!()}
1357 }
1358 ",
1359 )
1360 }
1361
1362 #[test]
add_function_with_string_literal_arg()1363 fn add_function_with_string_literal_arg() {
1364 check_assist(
1365 generate_function,
1366 r#"
1367 fn foo() {
1368 $0bar("bar")
1369 }
1370 "#,
1371 r#"
1372 fn foo() {
1373 bar("bar")
1374 }
1375
1376 fn bar(arg: &str) {
1377 ${0:todo!()}
1378 }
1379 "#,
1380 )
1381 }
1382
1383 #[test]
add_function_with_char_literal_arg()1384 fn add_function_with_char_literal_arg() {
1385 check_assist(
1386 generate_function,
1387 r#"
1388 fn foo() {
1389 $0bar('x')
1390 }
1391 "#,
1392 r#"
1393 fn foo() {
1394 bar('x')
1395 }
1396
1397 fn bar(arg: char) {
1398 ${0:todo!()}
1399 }
1400 "#,
1401 )
1402 }
1403
1404 #[test]
add_function_with_int_literal_arg()1405 fn add_function_with_int_literal_arg() {
1406 check_assist(
1407 generate_function,
1408 r"
1409 fn foo() {
1410 $0bar(42)
1411 }
1412 ",
1413 r"
1414 fn foo() {
1415 bar(42)
1416 }
1417
1418 fn bar(arg: i32) {
1419 ${0:todo!()}
1420 }
1421 ",
1422 )
1423 }
1424
1425 #[test]
add_function_with_cast_int_literal_arg()1426 fn add_function_with_cast_int_literal_arg() {
1427 check_assist(
1428 generate_function,
1429 r"
1430 fn foo() {
1431 $0bar(42 as u8)
1432 }
1433 ",
1434 r"
1435 fn foo() {
1436 bar(42 as u8)
1437 }
1438
1439 fn bar(arg: u8) {
1440 ${0:todo!()}
1441 }
1442 ",
1443 )
1444 }
1445
1446 #[test]
name_of_cast_variable_is_used()1447 fn name_of_cast_variable_is_used() {
1448 // Ensures that the name of the cast type isn't used
1449 // in the generated function signature.
1450 check_assist(
1451 generate_function,
1452 r"
1453 fn foo() {
1454 let x = 42;
1455 bar$0(x as u8)
1456 }
1457 ",
1458 r"
1459 fn foo() {
1460 let x = 42;
1461 bar(x as u8)
1462 }
1463
1464 fn bar(x: u8) {
1465 ${0:todo!()}
1466 }
1467 ",
1468 )
1469 }
1470
1471 #[test]
add_function_with_variable_arg()1472 fn add_function_with_variable_arg() {
1473 check_assist(
1474 generate_function,
1475 r"
1476 fn foo() {
1477 let worble = ();
1478 $0bar(worble)
1479 }
1480 ",
1481 r"
1482 fn foo() {
1483 let worble = ();
1484 bar(worble)
1485 }
1486
1487 fn bar(worble: ()) {
1488 ${0:todo!()}
1489 }
1490 ",
1491 )
1492 }
1493
1494 #[test]
add_function_with_impl_trait_arg()1495 fn add_function_with_impl_trait_arg() {
1496 check_assist(
1497 generate_function,
1498 r#"
1499 //- minicore: sized
1500 trait Foo {}
1501 fn foo() -> impl Foo {
1502 todo!()
1503 }
1504 fn baz() {
1505 $0bar(foo())
1506 }
1507 "#,
1508 r#"
1509 trait Foo {}
1510 fn foo() -> impl Foo {
1511 todo!()
1512 }
1513 fn baz() {
1514 bar(foo())
1515 }
1516
1517 fn bar(foo: impl Foo) {
1518 ${0:todo!()}
1519 }
1520 "#,
1521 )
1522 }
1523
1524 #[test]
borrowed_arg()1525 fn borrowed_arg() {
1526 check_assist(
1527 generate_function,
1528 r"
1529 struct Baz;
1530 fn baz() -> Baz { todo!() }
1531
1532 fn foo() {
1533 bar$0(&baz())
1534 }
1535 ",
1536 r"
1537 struct Baz;
1538 fn baz() -> Baz { todo!() }
1539
1540 fn foo() {
1541 bar(&baz())
1542 }
1543
1544 fn bar(baz: &Baz) {
1545 ${0:todo!()}
1546 }
1547 ",
1548 )
1549 }
1550
1551 #[test]
add_function_with_qualified_path_arg()1552 fn add_function_with_qualified_path_arg() {
1553 check_assist(
1554 generate_function,
1555 r"
1556 mod Baz {
1557 pub struct Bof;
1558 pub fn baz() -> Bof { Bof }
1559 }
1560 fn foo() {
1561 $0bar(Baz::baz())
1562 }
1563 ",
1564 r"
1565 mod Baz {
1566 pub struct Bof;
1567 pub fn baz() -> Bof { Bof }
1568 }
1569 fn foo() {
1570 bar(Baz::baz())
1571 }
1572
1573 fn bar(baz: Baz::Bof) {
1574 ${0:todo!()}
1575 }
1576 ",
1577 )
1578 }
1579
1580 #[test]
generate_function_with_generic_param()1581 fn generate_function_with_generic_param() {
1582 check_assist(
1583 generate_function,
1584 r"
1585 fn foo<T, const N: usize>(t: [T; N]) { $0bar(t) }
1586 ",
1587 r"
1588 fn foo<T, const N: usize>(t: [T; N]) { bar(t) }
1589
1590 fn bar<T, const N: usize>(t: [T; N]) {
1591 ${0:todo!()}
1592 }
1593 ",
1594 )
1595 }
1596
1597 #[test]
generate_function_with_parent_generic_param()1598 fn generate_function_with_parent_generic_param() {
1599 check_assist(
1600 generate_function,
1601 r"
1602 struct S<T>(T);
1603 impl<T> S<T> {
1604 fn foo<U>(t: T, u: U) { $0bar(t, u) }
1605 }
1606 ",
1607 r"
1608 struct S<T>(T);
1609 impl<T> S<T> {
1610 fn foo<U>(t: T, u: U) { bar(t, u) }
1611 }
1612
1613 fn bar<T, U>(t: T, u: U) {
1614 ${0:todo!()}
1615 }
1616 ",
1617 )
1618 }
1619
1620 #[test]
generic_param_in_receiver_type()1621 fn generic_param_in_receiver_type() {
1622 // FIXME: Generic parameter `T` should be part of impl, not method.
1623 check_assist(
1624 generate_function,
1625 r"
1626 struct S<T>(T);
1627 fn foo<T, U>(s: S<T>, u: U) { s.$0foo(u) }
1628 ",
1629 r"
1630 struct S<T>(T);
1631 impl S {
1632 fn foo<T, U>(&self, u: U) {
1633 ${0:todo!()}
1634 }
1635 }
1636 fn foo<T, U>(s: S<T>, u: U) { s.foo(u) }
1637 ",
1638 )
1639 }
1640
1641 #[test]
generic_param_in_return_type()1642 fn generic_param_in_return_type() {
1643 check_assist(
1644 generate_function,
1645 r"
1646 fn foo<T, const N: usize>() -> [T; N] { $0bar() }
1647 ",
1648 r"
1649 fn foo<T, const N: usize>() -> [T; N] { bar() }
1650
1651 fn bar<T, const N: usize>() -> [T; N] {
1652 ${0:todo!()}
1653 }
1654 ",
1655 )
1656 }
1657
1658 #[test]
generate_fn_with_bounds()1659 fn generate_fn_with_bounds() {
1660 // FIXME: where predicates should be on next lines.
1661 check_assist(
1662 generate_function,
1663 r"
1664 trait A<T> {}
1665 struct S<T>(T);
1666 impl<T: A<i32>> S<T>
1667 where
1668 T: A<i64>,
1669 {
1670 fn foo<U>(t: T, u: U)
1671 where
1672 T: A<()>,
1673 U: A<i32> + A<i64>,
1674 {
1675 $0bar(t, u)
1676 }
1677 }
1678 ",
1679 r"
1680 trait A<T> {}
1681 struct S<T>(T);
1682 impl<T: A<i32>> S<T>
1683 where
1684 T: A<i64>,
1685 {
1686 fn foo<U>(t: T, u: U)
1687 where
1688 T: A<()>,
1689 U: A<i32> + A<i64>,
1690 {
1691 bar(t, u)
1692 }
1693 }
1694
1695 fn bar<T: A<i32>, U>(t: T, u: U) where T: A<i64>, T: A<()>, U: A<i32> + A<i64> {
1696 ${0:todo!()}
1697 }
1698 ",
1699 )
1700 }
1701
1702 #[test]
include_transitive_param_dependency()1703 fn include_transitive_param_dependency() {
1704 // FIXME: where predicates should be on next lines.
1705 check_assist(
1706 generate_function,
1707 r"
1708 trait A<T> { type Assoc; }
1709 trait B { type Item; }
1710 struct S<T>(T);
1711 impl<T, U, V: B, W> S<(T, U, V, W)>
1712 where
1713 T: A<U, Assoc = V>,
1714 S<V::Item>: A<U, Assoc = W>,
1715 {
1716 fn foo<I>(t: T, u: U)
1717 where
1718 U: A<T, Assoc = I>,
1719 {
1720 $0bar(u)
1721 }
1722 }
1723 ",
1724 r"
1725 trait A<T> { type Assoc; }
1726 trait B { type Item; }
1727 struct S<T>(T);
1728 impl<T, U, V: B, W> S<(T, U, V, W)>
1729 where
1730 T: A<U, Assoc = V>,
1731 S<V::Item>: A<U, Assoc = W>,
1732 {
1733 fn foo<I>(t: T, u: U)
1734 where
1735 U: A<T, Assoc = I>,
1736 {
1737 bar(u)
1738 }
1739 }
1740
1741 fn 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> {
1742 ${0:todo!()}
1743 }
1744 ",
1745 )
1746 }
1747
1748 #[test]
irrelevant_bounds_are_filtered_out()1749 fn irrelevant_bounds_are_filtered_out() {
1750 check_assist(
1751 generate_function,
1752 r"
1753 trait A<T> {}
1754 struct S<T>(T);
1755 impl<T, U, V, W> S<(T, U, V, W)>
1756 where
1757 T: A<U>,
1758 V: A<W>,
1759 {
1760 fn foo<I>(t: T, u: U)
1761 where
1762 U: A<T> + A<I>,
1763 {
1764 $0bar(u)
1765 }
1766 }
1767 ",
1768 r"
1769 trait A<T> {}
1770 struct S<T>(T);
1771 impl<T, U, V, W> S<(T, U, V, W)>
1772 where
1773 T: A<U>,
1774 V: A<W>,
1775 {
1776 fn foo<I>(t: T, u: U)
1777 where
1778 U: A<T> + A<I>,
1779 {
1780 bar(u)
1781 }
1782 }
1783
1784 fn bar<T, U, I>(u: U) where T: A<U>, U: A<T> + A<I> {
1785 ${0:todo!()}
1786 }
1787 ",
1788 )
1789 }
1790
1791 #[test]
params_in_trait_arg_are_not_dependency()1792 fn params_in_trait_arg_are_not_dependency() {
1793 // Even though `bar` depends on `U` and `I`, we don't have to copy these bounds:
1794 // `T: A<I>` and `T: A<U>`.
1795 check_assist(
1796 generate_function,
1797 r"
1798 trait A<T> {}
1799 struct S<T>(T);
1800 impl<T, U> S<(T, U)>
1801 where
1802 T: A<U>,
1803 {
1804 fn foo<I>(t: T, u: U)
1805 where
1806 T: A<I>,
1807 U: A<I>,
1808 {
1809 $0bar(u)
1810 }
1811 }
1812 ",
1813 r"
1814 trait A<T> {}
1815 struct S<T>(T);
1816 impl<T, U> S<(T, U)>
1817 where
1818 T: A<U>,
1819 {
1820 fn foo<I>(t: T, u: U)
1821 where
1822 T: A<I>,
1823 U: A<I>,
1824 {
1825 bar(u)
1826 }
1827 }
1828
1829 fn bar<U, I>(u: U) where U: A<I> {
1830 ${0:todo!()}
1831 }
1832 ",
1833 )
1834 }
1835
1836 #[test]
dont_copy_bounds_already_in_scope()1837 fn dont_copy_bounds_already_in_scope() {
1838 check_assist(
1839 generate_function,
1840 r"
1841 trait A<T> {}
1842 struct S<T>(T);
1843 impl<T: A<i32>> S<T>
1844 where
1845 T: A<usize>,
1846 {
1847 fn foo<U: A<()>>(t: T, u: U)
1848 where
1849 T: A<S<i32>>,
1850 {
1851 Self::$0bar(t, u);
1852 }
1853 }
1854 ",
1855 r"
1856 trait A<T> {}
1857 struct S<T>(T);
1858 impl<T: A<i32>> S<T>
1859 where
1860 T: A<usize>,
1861 {
1862 fn foo<U: A<()>>(t: T, u: U)
1863 where
1864 T: A<S<i32>>,
1865 {
1866 Self::bar(t, u);
1867 }
1868
1869 fn bar<U: A<()>>(t: T, u: U) ${0:-> _} where T: A<S<i32>> {
1870 todo!()
1871 }
1872 }
1873 ",
1874 )
1875 }
1876
1877 #[test]
add_function_with_fn_arg()1878 fn add_function_with_fn_arg() {
1879 // FIXME: The argument in `bar` is wrong.
1880 check_assist(
1881 generate_function,
1882 r"
1883 struct Baz;
1884 impl Baz {
1885 fn new() -> Self { Baz }
1886 }
1887 fn foo() {
1888 $0bar(Baz::new);
1889 }
1890 ",
1891 r"
1892 struct Baz;
1893 impl Baz {
1894 fn new() -> Self { Baz }
1895 }
1896 fn foo() {
1897 bar(Baz::new);
1898 }
1899
1900 fn bar(new: fn) ${0:-> _} {
1901 todo!()
1902 }
1903 ",
1904 )
1905 }
1906
1907 #[test]
add_function_with_closure_arg()1908 fn add_function_with_closure_arg() {
1909 check_assist(
1910 generate_function,
1911 r"
1912 fn foo() {
1913 let closure = |x: i64| x - 1;
1914 $0bar(closure)
1915 }
1916 ",
1917 r"
1918 fn foo() {
1919 let closure = |x: i64| x - 1;
1920 bar(closure)
1921 }
1922
1923 fn bar(closure: impl Fn(i64) -> i64) {
1924 ${0:todo!()}
1925 }
1926 ",
1927 )
1928 }
1929
1930 #[test]
unresolveable_types_default_to_placeholder()1931 fn unresolveable_types_default_to_placeholder() {
1932 check_assist(
1933 generate_function,
1934 r"
1935 fn foo() {
1936 $0bar(baz)
1937 }
1938 ",
1939 r"
1940 fn foo() {
1941 bar(baz)
1942 }
1943
1944 fn bar(baz: _) {
1945 ${0:todo!()}
1946 }
1947 ",
1948 )
1949 }
1950
1951 #[test]
arg_names_dont_overlap()1952 fn arg_names_dont_overlap() {
1953 check_assist(
1954 generate_function,
1955 r"
1956 struct Baz;
1957 fn baz() -> Baz { Baz }
1958 fn foo() {
1959 $0bar(baz(), baz())
1960 }
1961 ",
1962 r"
1963 struct Baz;
1964 fn baz() -> Baz { Baz }
1965 fn foo() {
1966 bar(baz(), baz())
1967 }
1968
1969 fn bar(baz_1: Baz, baz_2: Baz) {
1970 ${0:todo!()}
1971 }
1972 ",
1973 )
1974 }
1975
1976 #[test]
arg_name_counters_start_at_1_per_name()1977 fn arg_name_counters_start_at_1_per_name() {
1978 check_assist(
1979 generate_function,
1980 r#"
1981 struct Baz;
1982 fn baz() -> Baz { Baz }
1983 fn foo() {
1984 $0bar(baz(), baz(), "foo", "bar")
1985 }
1986 "#,
1987 r#"
1988 struct Baz;
1989 fn baz() -> Baz { Baz }
1990 fn foo() {
1991 bar(baz(), baz(), "foo", "bar")
1992 }
1993
1994 fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
1995 ${0:todo!()}
1996 }
1997 "#,
1998 )
1999 }
2000
2001 #[test]
add_function_in_module()2002 fn add_function_in_module() {
2003 check_assist(
2004 generate_function,
2005 r"
2006 mod bar {}
2007
2008 fn foo() {
2009 bar::my_fn$0()
2010 }
2011 ",
2012 r"
2013 mod bar {
2014 pub(crate) fn my_fn() {
2015 ${0:todo!()}
2016 }
2017 }
2018
2019 fn foo() {
2020 bar::my_fn()
2021 }
2022 ",
2023 )
2024 }
2025
2026 #[test]
qualified_path_uses_correct_scope()2027 fn qualified_path_uses_correct_scope() {
2028 check_assist(
2029 generate_function,
2030 r#"
2031 mod foo {
2032 pub struct Foo;
2033 }
2034 fn bar() {
2035 use foo::Foo;
2036 let foo = Foo;
2037 baz$0(foo)
2038 }
2039 "#,
2040 r#"
2041 mod foo {
2042 pub struct Foo;
2043 }
2044 fn bar() {
2045 use foo::Foo;
2046 let foo = Foo;
2047 baz(foo)
2048 }
2049
2050 fn baz(foo: foo::Foo) {
2051 ${0:todo!()}
2052 }
2053 "#,
2054 )
2055 }
2056
2057 #[test]
qualified_path_in_generic_bounds_uses_correct_scope()2058 fn qualified_path_in_generic_bounds_uses_correct_scope() {
2059 check_assist(
2060 generate_function,
2061 r"
2062 mod a {
2063 pub trait A {};
2064 }
2065 pub mod b {
2066 pub struct S<T>(T);
2067 }
2068 struct S<T>(T);
2069 impl<T> S<T>
2070 where
2071 T: a::A,
2072 {
2073 fn foo<U: a::A>(t: b::S<T>, u: S<U>) {
2074 a::$0bar(t, u);
2075 }
2076 }
2077 ",
2078 r"
2079 mod a {
2080 pub trait A {}
2081
2082 pub(crate) fn bar<T, U: self::A>(t: crate::b::S<T>, u: crate::S<U>) ${0:-> _} where T: self::A {
2083 todo!()
2084 };
2085 }
2086 pub mod b {
2087 pub struct S<T>(T);
2088 }
2089 struct S<T>(T);
2090 impl<T> S<T>
2091 where
2092 T: a::A,
2093 {
2094 fn foo<U: a::A>(t: b::S<T>, u: S<U>) {
2095 a::bar(t, u);
2096 }
2097 }
2098 ",
2099 )
2100 }
2101 #[test]
add_function_in_module_containing_other_items()2102 fn add_function_in_module_containing_other_items() {
2103 check_assist(
2104 generate_function,
2105 r"
2106 mod bar {
2107 fn something_else() {}
2108 }
2109
2110 fn foo() {
2111 bar::my_fn$0()
2112 }
2113 ",
2114 r"
2115 mod bar {
2116 fn something_else() {}
2117
2118 pub(crate) fn my_fn() {
2119 ${0:todo!()}
2120 }
2121 }
2122
2123 fn foo() {
2124 bar::my_fn()
2125 }
2126 ",
2127 )
2128 }
2129
2130 #[test]
add_function_in_nested_module()2131 fn add_function_in_nested_module() {
2132 check_assist(
2133 generate_function,
2134 r"
2135 mod bar {
2136 pub mod baz {}
2137 }
2138
2139 fn foo() {
2140 bar::baz::my_fn$0()
2141 }
2142 ",
2143 r"
2144 mod bar {
2145 pub mod baz {
2146 pub(crate) fn my_fn() {
2147 ${0:todo!()}
2148 }
2149 }
2150 }
2151
2152 fn foo() {
2153 bar::baz::my_fn()
2154 }
2155 ",
2156 )
2157 }
2158
2159 #[test]
add_function_in_another_file()2160 fn add_function_in_another_file() {
2161 check_assist(
2162 generate_function,
2163 r"
2164 //- /main.rs
2165 mod foo;
2166
2167 fn main() {
2168 foo::bar$0()
2169 }
2170 //- /foo.rs
2171 ",
2172 r"
2173
2174
2175 pub(crate) fn bar() {
2176 ${0:todo!()}
2177 }",
2178 )
2179 }
2180
2181 #[test]
add_function_with_return_type()2182 fn add_function_with_return_type() {
2183 check_assist(
2184 generate_function,
2185 r"
2186 fn main() {
2187 let x: u32 = foo$0();
2188 }
2189 ",
2190 r"
2191 fn main() {
2192 let x: u32 = foo();
2193 }
2194
2195 fn foo() -> u32 {
2196 ${0:todo!()}
2197 }
2198 ",
2199 )
2200 }
2201
2202 #[test]
add_function_not_applicable_if_function_already_exists()2203 fn add_function_not_applicable_if_function_already_exists() {
2204 check_assist_not_applicable(
2205 generate_function,
2206 r"
2207 fn foo() {
2208 bar$0();
2209 }
2210
2211 fn bar() {}
2212 ",
2213 )
2214 }
2215
2216 #[test]
add_function_not_applicable_if_unresolved_variable_in_call_is_selected()2217 fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
2218 check_assist_not_applicable(
2219 // bar is resolved, but baz isn't.
2220 // The assist is only active if the cursor is on an unresolved path,
2221 // but the assist should only be offered if the path is a function call.
2222 generate_function,
2223 r#"
2224 fn foo() {
2225 bar(b$0az);
2226 }
2227
2228 fn bar(baz: ()) {}
2229 "#,
2230 )
2231 }
2232
2233 #[test]
create_method_with_no_args()2234 fn create_method_with_no_args() {
2235 check_assist(
2236 generate_function,
2237 r#"
2238 struct Foo;
2239 impl Foo {
2240 fn foo(&self) {
2241 self.bar()$0;
2242 }
2243 }
2244 "#,
2245 r#"
2246 struct Foo;
2247 impl Foo {
2248 fn foo(&self) {
2249 self.bar();
2250 }
2251
2252 fn bar(&self) ${0:-> _} {
2253 todo!()
2254 }
2255 }
2256 "#,
2257 )
2258 }
2259
2260 #[test]
create_function_with_async()2261 fn create_function_with_async() {
2262 check_assist(
2263 generate_function,
2264 r"
2265 async fn foo() {
2266 $0bar(42).await;
2267 }
2268 ",
2269 r"
2270 async fn foo() {
2271 bar(42).await;
2272 }
2273
2274 async fn bar(arg: i32) ${0:-> _} {
2275 todo!()
2276 }
2277 ",
2278 )
2279 }
2280
2281 #[test]
return_type_for_async_fn()2282 fn return_type_for_async_fn() {
2283 check_assist(
2284 generate_function,
2285 r"
2286 //- minicore: result
2287 async fn foo() {
2288 if Err(()) = $0bar(42).await {}
2289 }
2290 ",
2291 r"
2292 async fn foo() {
2293 if Err(()) = bar(42).await {}
2294 }
2295
2296 async fn bar(arg: i32) -> Result<_, ()> {
2297 ${0:todo!()}
2298 }
2299 ",
2300 );
2301 }
2302
2303 #[test]
create_method()2304 fn create_method() {
2305 check_assist(
2306 generate_function,
2307 r"
2308 struct S;
2309 fn foo() {S.bar$0();}
2310 ",
2311 r"
2312 struct S;
2313 impl S {
2314 fn bar(&self) ${0:-> _} {
2315 todo!()
2316 }
2317 }
2318 fn foo() {S.bar();}
2319 ",
2320 )
2321 }
2322
2323 #[test]
create_method_within_an_impl()2324 fn create_method_within_an_impl() {
2325 check_assist(
2326 generate_function,
2327 r"
2328 struct S;
2329 fn foo() {S.bar$0();}
2330 impl S {}
2331
2332 ",
2333 r"
2334 struct S;
2335 fn foo() {S.bar();}
2336 impl S {
2337 fn bar(&self) ${0:-> _} {
2338 todo!()
2339 }
2340 }
2341
2342 ",
2343 )
2344 }
2345
2346 #[test]
create_method_from_different_module()2347 fn create_method_from_different_module() {
2348 check_assist(
2349 generate_function,
2350 r"
2351 mod s {
2352 pub struct S;
2353 }
2354 fn foo() {s::S.bar$0();}
2355 ",
2356 r"
2357 mod s {
2358 pub struct S;
2359 impl S {
2360 pub(crate) fn bar(&self) ${0:-> _} {
2361 todo!()
2362 }
2363 }
2364 }
2365 fn foo() {s::S.bar();}
2366 ",
2367 )
2368 }
2369
2370 #[test]
create_method_from_descendant_module()2371 fn create_method_from_descendant_module() {
2372 check_assist(
2373 generate_function,
2374 r"
2375 struct S;
2376 mod s {
2377 fn foo() {
2378 super::S.bar$0();
2379 }
2380 }
2381
2382 ",
2383 r"
2384 struct S;
2385 impl S {
2386 fn bar(&self) ${0:-> _} {
2387 todo!()
2388 }
2389 }
2390 mod s {
2391 fn foo() {
2392 super::S.bar();
2393 }
2394 }
2395
2396 ",
2397 )
2398 }
2399
2400 #[test]
create_method_with_cursor_anywhere_on_call_expression()2401 fn create_method_with_cursor_anywhere_on_call_expression() {
2402 check_assist(
2403 generate_function,
2404 r"
2405 struct S;
2406 fn foo() {$0S.bar();}
2407 ",
2408 r"
2409 struct S;
2410 impl S {
2411 fn bar(&self) ${0:-> _} {
2412 todo!()
2413 }
2414 }
2415 fn foo() {S.bar();}
2416 ",
2417 )
2418 }
2419
2420 #[test]
create_async_method()2421 fn create_async_method() {
2422 check_assist(
2423 generate_function,
2424 r"
2425 //- minicore: result
2426 struct S;
2427 async fn foo() {
2428 if let Err(()) = S.$0bar(42).await {}
2429 }
2430 ",
2431 r"
2432 struct S;
2433 impl S {
2434 async fn bar(&self, arg: i32) -> Result<_, ()> {
2435 ${0:todo!()}
2436 }
2437 }
2438 async fn foo() {
2439 if let Err(()) = S.bar(42).await {}
2440 }
2441 ",
2442 )
2443 }
2444
2445 #[test]
create_static_method()2446 fn create_static_method() {
2447 check_assist(
2448 generate_function,
2449 r"
2450 struct S;
2451 fn foo() {S::bar$0();}
2452 ",
2453 r"
2454 struct S;
2455 impl S {
2456 fn bar() ${0:-> _} {
2457 todo!()
2458 }
2459 }
2460 fn foo() {S::bar();}
2461 ",
2462 )
2463 }
2464
2465 #[test]
create_async_static_method()2466 fn create_async_static_method() {
2467 check_assist(
2468 generate_function,
2469 r"
2470 //- minicore: result
2471 struct S;
2472 async fn foo() {
2473 if let Err(()) = S::$0bar(42).await {}
2474 }
2475 ",
2476 r"
2477 struct S;
2478 impl S {
2479 async fn bar(arg: i32) -> Result<_, ()> {
2480 ${0:todo!()}
2481 }
2482 }
2483 async fn foo() {
2484 if let Err(()) = S::bar(42).await {}
2485 }
2486 ",
2487 )
2488 }
2489
2490 #[test]
create_generic_static_method()2491 fn create_generic_static_method() {
2492 check_assist(
2493 generate_function,
2494 r"
2495 struct S;
2496 fn foo<T, const N: usize>(t: [T; N]) { S::bar$0(t); }
2497 ",
2498 r"
2499 struct S;
2500 impl S {
2501 fn bar<T, const N: usize>(t: [T; N]) ${0:-> _} {
2502 todo!()
2503 }
2504 }
2505 fn foo<T, const N: usize>(t: [T; N]) { S::bar(t); }
2506 ",
2507 )
2508 }
2509
2510 #[test]
create_static_method_within_an_impl()2511 fn create_static_method_within_an_impl() {
2512 check_assist(
2513 generate_function,
2514 r"
2515 struct S;
2516 fn foo() {S::bar$0();}
2517 impl S {}
2518
2519 ",
2520 r"
2521 struct S;
2522 fn foo() {S::bar();}
2523 impl S {
2524 fn bar() ${0:-> _} {
2525 todo!()
2526 }
2527 }
2528
2529 ",
2530 )
2531 }
2532
2533 #[test]
create_static_method_from_different_module()2534 fn create_static_method_from_different_module() {
2535 check_assist(
2536 generate_function,
2537 r"
2538 mod s {
2539 pub struct S;
2540 }
2541 fn foo() {s::S::bar$0();}
2542 ",
2543 r"
2544 mod s {
2545 pub struct S;
2546 impl S {
2547 pub(crate) fn bar() ${0:-> _} {
2548 todo!()
2549 }
2550 }
2551 }
2552 fn foo() {s::S::bar();}
2553 ",
2554 )
2555 }
2556
2557 #[test]
create_static_method_with_cursor_anywhere_on_call_expression()2558 fn create_static_method_with_cursor_anywhere_on_call_expression() {
2559 check_assist(
2560 generate_function,
2561 r"
2562 struct S;
2563 fn foo() {$0S::bar();}
2564 ",
2565 r"
2566 struct S;
2567 impl S {
2568 fn bar() ${0:-> _} {
2569 todo!()
2570 }
2571 }
2572 fn foo() {S::bar();}
2573 ",
2574 )
2575 }
2576
2577 #[test]
create_static_method_within_an_impl_with_self_syntax()2578 fn create_static_method_within_an_impl_with_self_syntax() {
2579 check_assist(
2580 generate_function,
2581 r"
2582 struct S;
2583 impl S {
2584 fn foo(&self) {
2585 Self::bar$0();
2586 }
2587 }
2588 ",
2589 r"
2590 struct S;
2591 impl S {
2592 fn foo(&self) {
2593 Self::bar();
2594 }
2595
2596 fn bar() ${0:-> _} {
2597 todo!()
2598 }
2599 }
2600 ",
2601 )
2602 }
2603
2604 #[test]
no_panic_on_invalid_global_path()2605 fn no_panic_on_invalid_global_path() {
2606 check_assist(
2607 generate_function,
2608 r"
2609 fn main() {
2610 ::foo$0();
2611 }
2612 ",
2613 r"
2614 fn main() {
2615 ::foo();
2616 }
2617
2618 fn foo() ${0:-> _} {
2619 todo!()
2620 }
2621 ",
2622 )
2623 }
2624
2625 #[test]
handle_tuple_indexing()2626 fn handle_tuple_indexing() {
2627 check_assist(
2628 generate_function,
2629 r"
2630 fn main() {
2631 let a = ((),);
2632 foo$0(a.0);
2633 }
2634 ",
2635 r"
2636 fn main() {
2637 let a = ((),);
2638 foo(a.0);
2639 }
2640
2641 fn foo(a: ()) ${0:-> _} {
2642 todo!()
2643 }
2644 ",
2645 )
2646 }
2647
2648 #[test]
add_function_with_const_arg()2649 fn add_function_with_const_arg() {
2650 check_assist(
2651 generate_function,
2652 r"
2653 const VALUE: usize = 0;
2654 fn main() {
2655 foo$0(VALUE);
2656 }
2657 ",
2658 r"
2659 const VALUE: usize = 0;
2660 fn main() {
2661 foo(VALUE);
2662 }
2663
2664 fn foo(value: usize) ${0:-> _} {
2665 todo!()
2666 }
2667 ",
2668 )
2669 }
2670
2671 #[test]
add_function_with_static_arg()2672 fn add_function_with_static_arg() {
2673 check_assist(
2674 generate_function,
2675 r"
2676 static VALUE: usize = 0;
2677 fn main() {
2678 foo$0(VALUE);
2679 }
2680 ",
2681 r"
2682 static VALUE: usize = 0;
2683 fn main() {
2684 foo(VALUE);
2685 }
2686
2687 fn foo(value: usize) ${0:-> _} {
2688 todo!()
2689 }
2690 ",
2691 )
2692 }
2693
2694 #[test]
add_function_with_static_mut_arg()2695 fn add_function_with_static_mut_arg() {
2696 check_assist(
2697 generate_function,
2698 r"
2699 static mut VALUE: usize = 0;
2700 fn main() {
2701 foo$0(VALUE);
2702 }
2703 ",
2704 r"
2705 static mut VALUE: usize = 0;
2706 fn main() {
2707 foo(VALUE);
2708 }
2709
2710 fn foo(value: usize) ${0:-> _} {
2711 todo!()
2712 }
2713 ",
2714 )
2715 }
2716
2717 #[test]
not_applicable_for_enum_variant()2718 fn not_applicable_for_enum_variant() {
2719 check_assist_not_applicable(
2720 generate_function,
2721 r"
2722 enum Foo {}
2723 fn main() {
2724 Foo::Bar$0(true)
2725 }
2726 ",
2727 );
2728 }
2729
2730 #[test]
applicable_for_enum_method()2731 fn applicable_for_enum_method() {
2732 check_assist(
2733 generate_function,
2734 r"
2735 enum Foo {}
2736 fn main() {
2737 Foo::new$0();
2738 }
2739 ",
2740 r"
2741 enum Foo {}
2742 impl Foo {
2743 fn new() ${0:-> _} {
2744 todo!()
2745 }
2746 }
2747 fn main() {
2748 Foo::new();
2749 }
2750 ",
2751 )
2752 }
2753
2754 #[test]
applicable_in_different_local_crate()2755 fn applicable_in_different_local_crate() {
2756 check_assist(
2757 generate_function,
2758 r"
2759 //- /lib.rs crate:lib new_source_root:local
2760 fn dummy() {}
2761 //- /main.rs crate:main deps:lib new_source_root:local
2762 fn main() {
2763 lib::foo$0();
2764 }
2765 ",
2766 r"
2767 fn dummy() {}
2768
2769 pub fn foo() ${0:-> _} {
2770 todo!()
2771 }
2772 ",
2773 );
2774 }
2775
2776 #[test]
applicable_in_different_local_crate_method()2777 fn applicable_in_different_local_crate_method() {
2778 check_assist(
2779 generate_function,
2780 r"
2781 //- /lib.rs crate:lib new_source_root:local
2782 pub struct S;
2783 //- /main.rs crate:main deps:lib new_source_root:local
2784 fn main() {
2785 lib::S.foo$0();
2786 }
2787 ",
2788 r"
2789 pub struct S;
2790 impl S {
2791 pub fn foo(&self) ${0:-> _} {
2792 todo!()
2793 }
2794 }
2795 ",
2796 );
2797 }
2798
2799 #[test]
not_applicable_in_different_library_crate()2800 fn not_applicable_in_different_library_crate() {
2801 check_assist_not_applicable(
2802 generate_function,
2803 r"
2804 //- /lib.rs crate:lib new_source_root:library
2805 fn dummy() {}
2806 //- /main.rs crate:main deps:lib new_source_root:local
2807 fn main() {
2808 lib::foo$0();
2809 }
2810 ",
2811 );
2812 }
2813
2814 #[test]
not_applicable_in_different_library_crate_method()2815 fn not_applicable_in_different_library_crate_method() {
2816 check_assist_not_applicable(
2817 generate_function,
2818 r"
2819 //- /lib.rs crate:lib new_source_root:library
2820 pub struct S;
2821 //- /main.rs crate:main deps:lib new_source_root:local
2822 fn main() {
2823 lib::S.foo$0();
2824 }
2825 ",
2826 );
2827 }
2828 }
2829