]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
Auto merge of #98626 - oli-obk:tracing, r=lcnr
[rust.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / generate_documentation_template.rs
1 use hir::{AsAssocItem, HasVisibility, ModuleDef, Visibility};
2 use ide_db::assists::{AssistId, AssistKind};
3 use itertools::Itertools;
4 use stdx::{format_to, to_lower_snake_case};
5 use syntax::{
6     algo::skip_whitespace_token,
7     ast::{self, edit::IndentLevel, HasDocComments, HasName},
8     match_ast, AstNode, AstToken,
9 };
10
11 use crate::assist_context::{AssistContext, Assists};
12
13 // Assist: generate_documentation_template
14 //
15 // Adds a documentation template above a function definition / declaration.
16 //
17 // ```
18 // pub struct S;
19 // impl S {
20 //     pub unsafe fn set_len$0(&mut self, len: usize) -> Result<(), std::io::Error> {
21 //         /* ... */
22 //     }
23 // }
24 // ```
25 // ->
26 // ```
27 // pub struct S;
28 // impl S {
29 //     /// Sets the length of this [`S`].
30 //     ///
31 //     /// # Errors
32 //     ///
33 //     /// This function will return an error if .
34 //     ///
35 //     /// # Safety
36 //     ///
37 //     /// .
38 //     pub unsafe fn set_len(&mut self, len: usize) -> Result<(), std::io::Error> {
39 //         /* ... */
40 //     }
41 // }
42 // ```
43 pub(crate) fn generate_documentation_template(
44     acc: &mut Assists,
45     ctx: &AssistContext<'_>,
46 ) -> Option<()> {
47     let name = ctx.find_node_at_offset::<ast::Name>()?;
48     let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
49     if is_in_trait_impl(&ast_func, ctx) || ast_func.doc_comments().next().is_some() {
50         return None;
51     }
52
53     let parent_syntax = ast_func.syntax();
54     let text_range = parent_syntax.text_range();
55     let indent_level = IndentLevel::from_node(parent_syntax);
56
57     acc.add(
58         AssistId("generate_documentation_template", AssistKind::Generate),
59         "Generate a documentation template",
60         text_range,
61         |builder| {
62             // Introduction / short function description before the sections
63             let mut doc_lines = vec![introduction_builder(&ast_func, ctx).unwrap_or(".".into())];
64             // Then come the sections
65             for section_builder in [panics_builder, errors_builder, safety_builder] {
66                 if let Some(mut lines) = section_builder(&ast_func) {
67                     doc_lines.push("".into());
68                     doc_lines.append(&mut lines);
69                 }
70             }
71             builder.insert(text_range.start(), documentation_from_lines(doc_lines, indent_level));
72         },
73     )
74 }
75
76 // Assist: generate_doc_example
77 //
78 // Generates a rustdoc example when editing an item's documentation.
79 //
80 // ```
81 // /// Adds two numbers.$0
82 // pub fn add(a: i32, b: i32) -> i32 { a + b }
83 // ```
84 // ->
85 // ```
86 // /// Adds two numbers.
87 // ///
88 // /// # Examples
89 // ///
90 // /// ```
91 // /// use test::add;
92 // ///
93 // /// assert_eq!(add(a, b), );
94 // /// ```
95 // pub fn add(a: i32, b: i32) -> i32 { a + b }
96 // ```
97 pub(crate) fn generate_doc_example(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
98     let tok: ast::Comment = ctx.find_token_at_offset()?;
99     let node = tok.syntax().parent()?;
100     let last_doc_token =
101         ast::AnyHasDocComments::cast(node.clone())?.doc_comments().last()?.syntax().clone();
102     let next_token = skip_whitespace_token(last_doc_token.next_token()?, syntax::Direction::Next)?;
103
104     let example = match_ast! {
105         match node {
106             ast::Fn(it) => make_example_for_fn(&it, ctx)?,
107             _ => return None,
108         }
109     };
110
111     let mut lines = string_vec_from(&["", "# Examples", "", "```"]);
112     lines.extend(example.lines().map(String::from));
113     lines.push("```".into());
114     let indent_level = IndentLevel::from_node(&node);
115
116     acc.add(
117         AssistId("generate_doc_example", AssistKind::Generate),
118         "Generate a documentation example",
119         node.text_range(),
120         |builder| {
121             builder.insert(
122                 next_token.text_range().start(),
123                 documentation_from_lines(lines, indent_level),
124             );
125         },
126     )
127 }
128
129 fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
130     if !is_public(ast_func, ctx)? {
131         // Doctests for private items can't actually name the item, so they're pretty useless.
132         return None;
133     }
134
135     if is_in_trait_def(ast_func, ctx) {
136         // This is not yet implemented.
137         return None;
138     }
139
140     let mut example = String::new();
141
142     let is_unsafe = ast_func.unsafe_token().is_some();
143     let param_list = ast_func.param_list()?;
144     let ref_mut_params = ref_mut_params(&param_list);
145     let self_name = self_name(ast_func);
146
147     format_to!(example, "use {};\n\n", build_path(ast_func, ctx)?);
148     if let Some(self_name) = &self_name {
149         if let Some(mtbl) = is_ref_mut_self(ast_func) {
150             let mtbl = if mtbl == true { " mut" } else { "" };
151             format_to!(example, "let{} {} = ;\n", mtbl, self_name);
152         }
153     }
154     for param_name in &ref_mut_params {
155         format_to!(example, "let mut {} = ;\n", param_name);
156     }
157     // Call the function, check result
158     let function_call = function_call(ast_func, &param_list, self_name.as_deref(), is_unsafe)?;
159     if returns_a_value(ast_func, ctx) {
160         if count_parameters(&param_list) < 3 {
161             format_to!(example, "assert_eq!({}, );\n", function_call);
162         } else {
163             format_to!(example, "let result = {};\n", function_call);
164             example.push_str("assert_eq!(result, );\n");
165         }
166     } else {
167         format_to!(example, "{};\n", function_call);
168     }
169     // Check the mutated values
170     if is_ref_mut_self(ast_func) == Some(true) {
171         format_to!(example, "assert_eq!({}, );", self_name?);
172     }
173     for param_name in &ref_mut_params {
174         format_to!(example, "assert_eq!({}, );", param_name);
175     }
176     Some(example)
177 }
178
179 fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
180     let hir_func = ctx.sema.to_def(ast_func)?;
181     let container = hir_func.as_assoc_item(ctx.db())?.container(ctx.db());
182     if let hir::AssocItemContainer::Impl(imp) = container {
183         let ret_ty = hir_func.ret_type(ctx.db());
184         let self_ty = imp.self_ty(ctx.db());
185         let name = ast_func.name()?.to_string();
186         let linkable_self_ty = self_type_without_lifetimes(ast_func);
187         let linkable_self_ty = linkable_self_ty.as_deref();
188
189         let intro_for_new = || {
190             let is_new = name == "new";
191             if is_new && ret_ty == self_ty {
192                 Some(format!("Creates a new [`{}`].", linkable_self_ty?))
193             } else {
194                 None
195             }
196         };
197
198         let intro_for_getter = || match (
199             hir_func.self_param(ctx.sema.db),
200             &*hir_func.params_without_self(ctx.sema.db),
201         ) {
202             (Some(self_param), []) if self_param.access(ctx.sema.db) != hir::Access::Owned => {
203                 if name.starts_with("as_") || name.starts_with("to_") || name == "get" {
204                     return None;
205                 }
206                 let mut what = name.trim_end_matches("_mut").replace('_', " ");
207                 if what == "len" {
208                     what = "length".into()
209                 }
210                 let reference = if ret_ty.is_mutable_reference() {
211                     " a mutable reference to"
212                 } else if ret_ty.is_reference() {
213                     " a reference to"
214                 } else {
215                     ""
216                 };
217                 Some(format!("Returns{reference} the {what} of this [`{}`].", linkable_self_ty?))
218             }
219             _ => None,
220         };
221
222         let intro_for_setter = || {
223             if !name.starts_with("set_") {
224                 return None;
225             }
226
227             let mut what = name.trim_start_matches("set_").replace('_', " ");
228             if what == "len" {
229                 what = "length".into()
230             };
231             Some(format!("Sets the {what} of this [`{}`].", linkable_self_ty?))
232         };
233
234         if let Some(intro) = intro_for_new() {
235             return Some(intro);
236         }
237         if let Some(intro) = intro_for_getter() {
238             return Some(intro);
239         }
240         if let Some(intro) = intro_for_setter() {
241             return Some(intro);
242         }
243     }
244     None
245 }
246
247 /// Builds an optional `# Panics` section
248 fn panics_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
249     match can_panic(ast_func) {
250         Some(true) => Some(string_vec_from(&["# Panics", "", "Panics if ."])),
251         _ => None,
252     }
253 }
254
255 /// Builds an optional `# Errors` section
256 fn errors_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
257     match return_type(ast_func)?.to_string().contains("Result") {
258         true => Some(string_vec_from(&["# Errors", "", "This function will return an error if ."])),
259         false => None,
260     }
261 }
262
263 /// Builds an optional `# Safety` section
264 fn safety_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
265     let is_unsafe = ast_func.unsafe_token().is_some();
266     match is_unsafe {
267         true => Some(string_vec_from(&["# Safety", "", "."])),
268         false => None,
269     }
270 }
271
272 /// Checks if the function is public / exported
273 fn is_public(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<bool> {
274     let hir_func = ctx.sema.to_def(ast_func)?;
275     Some(
276         hir_func.visibility(ctx.db()) == Visibility::Public
277             && all_parent_mods_public(&hir_func, ctx),
278     )
279 }
280
281 /// Checks that all parent modules of the function are public / exported
282 fn all_parent_mods_public(hir_func: &hir::Function, ctx: &AssistContext<'_>) -> bool {
283     let mut module = hir_func.module(ctx.db());
284     loop {
285         if let Some(parent) = module.parent(ctx.db()) {
286             match ModuleDef::from(module).visibility(ctx.db()) {
287                 Visibility::Public => module = parent,
288                 _ => break false,
289             }
290         } else {
291             break true;
292         }
293     }
294 }
295
296 /// Returns the name of the current crate
297 fn crate_name(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
298     let krate = ctx.sema.scope(ast_func.syntax())?.krate();
299     Some(krate.display_name(ctx.db())?.to_string())
300 }
301
302 /// `None` if function without a body; some bool to guess if function can panic
303 fn can_panic(ast_func: &ast::Fn) -> Option<bool> {
304     let body = ast_func.body()?.to_string();
305     let can_panic = body.contains("panic!(")
306         // FIXME it would be better to not match `debug_assert*!` macro invocations
307         || body.contains("assert!(")
308         || body.contains(".unwrap()")
309         || body.contains(".expect(");
310     Some(can_panic)
311 }
312
313 /// Helper function to get the name that should be given to `self` arguments
314 fn self_name(ast_func: &ast::Fn) -> Option<String> {
315     self_partial_type(ast_func).map(|name| to_lower_snake_case(&name))
316 }
317
318 /// Heper function to get the name of the type of `self`
319 fn self_type(ast_func: &ast::Fn) -> Option<ast::Type> {
320     ast_func.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty())
321 }
322
323 /// Output the real name of `Self` like `MyType<T>`, without the lifetimes.
324 fn self_type_without_lifetimes(ast_func: &ast::Fn) -> Option<String> {
325     let path_segment = match self_type(ast_func)? {
326         ast::Type::PathType(path_type) => path_type.path()?.segment()?,
327         _ => return None,
328     };
329     let mut name = path_segment.name_ref()?.to_string();
330     let generics = path_segment.generic_arg_list().into_iter().flat_map(|list| {
331         list.generic_args()
332             .filter(|generic| matches!(generic, ast::GenericArg::TypeArg(_)))
333             .map(|generic| generic.to_string())
334     });
335     let generics: String = generics.format(", ").to_string();
336     if !generics.is_empty() {
337         name.push('<');
338         name.push_str(&generics);
339         name.push('>');
340     }
341     Some(name)
342 }
343
344 /// Heper function to get the name of the type of `self` without generic arguments
345 fn self_partial_type(ast_func: &ast::Fn) -> Option<String> {
346     let mut self_type = self_type(ast_func)?.to_string();
347     if let Some(idx) = self_type.find(|c| ['<', ' '].contains(&c)) {
348         self_type.truncate(idx);
349     }
350     Some(self_type)
351 }
352
353 /// Helper function to determine if the function is in a trait implementation
354 fn is_in_trait_impl(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
355     ctx.sema
356         .to_def(ast_func)
357         .and_then(|hir_func| hir_func.as_assoc_item(ctx.db()))
358         .and_then(|assoc_item| assoc_item.containing_trait_impl(ctx.db()))
359         .is_some()
360 }
361
362 /// Helper function to determine if the function definition is in a trait definition
363 fn is_in_trait_def(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
364     ctx.sema
365         .to_def(ast_func)
366         .and_then(|hir_func| hir_func.as_assoc_item(ctx.db()))
367         .and_then(|assoc_item| assoc_item.containing_trait(ctx.db()))
368         .is_some()
369 }
370
371 /// Returns `None` if no `self` at all, `Some(true)` if there is `&mut self` else `Some(false)`
372 fn is_ref_mut_self(ast_func: &ast::Fn) -> Option<bool> {
373     let self_param = ast_func.param_list()?.self_param()?;
374     Some(self_param.mut_token().is_some() && self_param.amp_token().is_some())
375 }
376
377 /// Helper function to determine if a parameter is `&mut`
378 fn is_a_ref_mut_param(param: &ast::Param) -> bool {
379     match param.ty() {
380         Some(ast::Type::RefType(param_ref)) => param_ref.mut_token().is_some(),
381         _ => false,
382     }
383 }
384
385 /// Helper function to build the list of `&mut` parameters
386 fn ref_mut_params(param_list: &ast::ParamList) -> Vec<String> {
387     param_list
388         .params()
389         .filter_map(|param| match is_a_ref_mut_param(&param) {
390             // Maybe better filter the param name (to do this maybe extract a function from
391             // `arguments_from_params`?) in case of a `mut a: &mut T`. Anyway managing most (not
392             // all) cases might be enough, the goal is just to produce a template.
393             true => Some(param.pat()?.to_string()),
394             false => None,
395         })
396         .collect()
397 }
398
399 /// Helper function to build the comma-separated list of arguments of the function
400 fn arguments_from_params(param_list: &ast::ParamList) -> String {
401     let args_iter = param_list.params().map(|param| match param.pat() {
402         // To avoid `mut` in the function call (which would be a nonsense), `Pat` should not be
403         // written as is so its variants must be managed independently. Other variants (for
404         // instance `TuplePat`) could be managed later.
405         Some(ast::Pat::IdentPat(ident_pat)) => match ident_pat.name() {
406             Some(name) => match is_a_ref_mut_param(&param) {
407                 true => format!("&mut {}", name),
408                 false => name.to_string(),
409             },
410             None => "_".to_string(),
411         },
412         _ => "_".to_string(),
413     });
414     args_iter.format(", ").to_string()
415 }
416
417 /// Helper function to build a function call. `None` if expected `self_name` was not provided
418 fn function_call(
419     ast_func: &ast::Fn,
420     param_list: &ast::ParamList,
421     self_name: Option<&str>,
422     is_unsafe: bool,
423 ) -> Option<String> {
424     let name = ast_func.name()?;
425     let arguments = arguments_from_params(param_list);
426     let function_call = if param_list.self_param().is_some() {
427         format!("{}.{}({})", self_name?, name, arguments)
428     } else if let Some(implementation) = self_partial_type(ast_func) {
429         format!("{}::{}({})", implementation, name, arguments)
430     } else {
431         format!("{}({})", name, arguments)
432     };
433     match is_unsafe {
434         true => Some(format!("unsafe {{ {} }}", function_call)),
435         false => Some(function_call),
436     }
437 }
438
439 /// Helper function to count the parameters including `self`
440 fn count_parameters(param_list: &ast::ParamList) -> usize {
441     param_list.params().count() + if param_list.self_param().is_some() { 1 } else { 0 }
442 }
443
444 /// Helper function to transform lines of documentation into a Rust code documentation
445 fn documentation_from_lines(doc_lines: Vec<String>, indent_level: IndentLevel) -> String {
446     let mut result = String::new();
447     for doc_line in doc_lines {
448         result.push_str("///");
449         if !doc_line.is_empty() {
450             result.push(' ');
451             result.push_str(&doc_line);
452         }
453         result.push('\n');
454         result.push_str(&indent_level.to_string());
455     }
456     result
457 }
458
459 /// Helper function to transform an array of borrowed strings to an owned `Vec<String>`
460 fn string_vec_from(string_array: &[&str]) -> Vec<String> {
461     string_array.iter().map(|&s| s.to_owned()).collect()
462 }
463
464 /// Helper function to build the path of the module in the which is the node
465 fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
466     let crate_name = crate_name(ast_func, ctx)?;
467     let leaf = self_partial_type(ast_func)
468         .or_else(|| ast_func.name().map(|n| n.to_string()))
469         .unwrap_or_else(|| "*".into());
470     let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into();
471     match module_def.canonical_path(ctx.db()) {
472         Some(path) => Some(format!("{}::{}::{}", crate_name, path, leaf)),
473         None => Some(format!("{}::{}", crate_name, leaf)),
474     }
475 }
476
477 /// Helper function to get the return type of a function
478 fn return_type(ast_func: &ast::Fn) -> Option<ast::Type> {
479     ast_func.ret_type()?.ty()
480 }
481
482 /// Helper function to determine if the function returns some data
483 fn returns_a_value(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
484     ctx.sema
485         .to_def(ast_func)
486         .map(|hir_func| hir_func.ret_type(ctx.db()))
487         .map(|ret_ty| !ret_ty.is_unit() && !ret_ty.is_never())
488         .unwrap_or(false)
489 }
490
491 #[cfg(test)]
492 mod tests {
493     use crate::tests::{check_assist, check_assist_not_applicable};
494
495     use super::*;
496
497     #[test]
498     fn not_applicable_on_function_calls() {
499         check_assist_not_applicable(
500             generate_documentation_template,
501             r#"
502 fn hello_world() {}
503 fn calls_hello_world() {
504     hello_world$0();
505 }
506 "#,
507         )
508     }
509
510     #[test]
511     fn not_applicable_in_trait_impl() {
512         check_assist_not_applicable(
513             generate_documentation_template,
514             r#"
515 trait MyTrait {}
516 struct MyStruct;
517 impl MyTrait for MyStruct {
518     fn hello_world$0();
519 }
520 "#,
521         )
522     }
523
524     #[test]
525     fn not_applicable_if_function_already_documented() {
526         check_assist_not_applicable(
527             generate_documentation_template,
528             r#"
529 /// Some documentation here
530 pub fn $0documented_function() {}
531 "#,
532         );
533     }
534
535     #[test]
536     fn supports_noop_function() {
537         check_assist(
538             generate_documentation_template,
539             r#"
540 pub fn no$0op() {}
541 "#,
542             r#"
543 /// .
544 pub fn noop() {}
545 "#,
546         );
547     }
548
549     #[test]
550     fn is_applicable_if_function_is_private() {
551         check_assist(
552             generate_documentation_template,
553             r#"
554 fn priv$0ate() {}
555 "#,
556             r#"
557 /// .
558 fn private() {}
559 "#,
560         );
561     }
562
563     #[test]
564     fn no_doc_example_for_private_fn() {
565         check_assist_not_applicable(
566             generate_doc_example,
567             r#"
568 ///$0
569 fn private() {}
570 "#,
571         );
572     }
573
574     #[test]
575     fn supports_a_parameter() {
576         check_assist(
577             generate_doc_example,
578             r#"
579 /// $0.
580 pub fn noop_with_param(_a: i32) {}
581 "#,
582             r#"
583 /// .
584 ///
585 /// # Examples
586 ///
587 /// ```
588 /// use test::noop_with_param;
589 ///
590 /// noop_with_param(_a);
591 /// ```
592 pub fn noop_with_param(_a: i32) {}
593 "#,
594         );
595     }
596
597     #[test]
598     fn detects_unsafe_function() {
599         check_assist(
600             generate_documentation_template,
601             r#"
602 pub unsafe fn no$0op_unsafe() {}
603 "#,
604             r#"
605 /// .
606 ///
607 /// # Safety
608 ///
609 /// .
610 pub unsafe fn noop_unsafe() {}
611 "#,
612         );
613         check_assist(
614             generate_doc_example,
615             r#"
616 /// .
617 ///
618 /// # Safety$0
619 ///
620 /// .
621 pub unsafe fn noop_unsafe() {}
622 "#,
623             r#"
624 /// .
625 ///
626 /// # Safety
627 ///
628 /// .
629 ///
630 /// # Examples
631 ///
632 /// ```
633 /// use test::noop_unsafe;
634 ///
635 /// unsafe { noop_unsafe() };
636 /// ```
637 pub unsafe fn noop_unsafe() {}
638 "#,
639         );
640     }
641
642     #[test]
643     fn guesses_panic_macro_can_panic() {
644         check_assist(
645             generate_documentation_template,
646             r#"
647 pub fn panic$0s_if(a: bool) {
648     if a {
649         panic!();
650     }
651 }
652 "#,
653             r#"
654 /// .
655 ///
656 /// # Panics
657 ///
658 /// Panics if .
659 pub fn panics_if(a: bool) {
660     if a {
661         panic!();
662     }
663 }
664 "#,
665         );
666     }
667
668     #[test]
669     fn guesses_assert_macro_can_panic() {
670         check_assist(
671             generate_documentation_template,
672             r#"
673 pub fn $0panics_if_not(a: bool) {
674     assert!(a == true);
675 }
676 "#,
677             r#"
678 /// .
679 ///
680 /// # Panics
681 ///
682 /// Panics if .
683 pub fn panics_if_not(a: bool) {
684     assert!(a == true);
685 }
686 "#,
687         );
688     }
689
690     #[test]
691     fn guesses_unwrap_can_panic() {
692         check_assist(
693             generate_documentation_template,
694             r#"
695 pub fn $0panics_if_none(a: Option<()>) {
696     a.unwrap();
697 }
698 "#,
699             r#"
700 /// .
701 ///
702 /// # Panics
703 ///
704 /// Panics if .
705 pub fn panics_if_none(a: Option<()>) {
706     a.unwrap();
707 }
708 "#,
709         );
710     }
711
712     #[test]
713     fn guesses_expect_can_panic() {
714         check_assist(
715             generate_documentation_template,
716             r#"
717 pub fn $0panics_if_none2(a: Option<()>) {
718     a.expect("Bouh!");
719 }
720 "#,
721             r#"
722 /// .
723 ///
724 /// # Panics
725 ///
726 /// Panics if .
727 pub fn panics_if_none2(a: Option<()>) {
728     a.expect("Bouh!");
729 }
730 "#,
731         );
732     }
733
734     #[test]
735     fn checks_output_in_example() {
736         check_assist(
737             generate_doc_example,
738             r#"
739 ///$0
740 pub fn returns_a_value$0() -> i32 {
741     0
742 }
743 "#,
744             r#"
745 ///
746 ///
747 /// # Examples
748 ///
749 /// ```
750 /// use test::returns_a_value;
751 ///
752 /// assert_eq!(returns_a_value(), );
753 /// ```
754 pub fn returns_a_value() -> i32 {
755     0
756 }
757 "#,
758         );
759     }
760
761     #[test]
762     fn detects_result_output() {
763         check_assist(
764             generate_documentation_template,
765             r#"
766 pub fn returns_a_result$0() -> Result<i32, std::io::Error> {
767     Ok(0)
768 }
769 "#,
770             r#"
771 /// .
772 ///
773 /// # Errors
774 ///
775 /// This function will return an error if .
776 pub fn returns_a_result() -> Result<i32, std::io::Error> {
777     Ok(0)
778 }
779 "#,
780         );
781     }
782
783     #[test]
784     fn checks_ref_mut_in_example() {
785         check_assist(
786             generate_doc_example,
787             r#"
788 ///$0
789 pub fn modifies_a_value$0(a: &mut i32) {
790     *a = 0;
791 }
792 "#,
793             r#"
794 ///
795 ///
796 /// # Examples
797 ///
798 /// ```
799 /// use test::modifies_a_value;
800 ///
801 /// let mut a = ;
802 /// modifies_a_value(&mut a);
803 /// assert_eq!(a, );
804 /// ```
805 pub fn modifies_a_value(a: &mut i32) {
806     *a = 0;
807 }
808 "#,
809         );
810     }
811
812     #[test]
813     fn stores_result_if_at_least_3_params() {
814         check_assist(
815             generate_doc_example,
816             r#"
817 ///$0
818 pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
819     a + b + c
820 }
821 "#,
822             r#"
823 ///
824 ///
825 /// # Examples
826 ///
827 /// ```
828 /// use test::sum3;
829 ///
830 /// let result = sum3(a, b, c);
831 /// assert_eq!(result, );
832 /// ```
833 pub fn sum3(a: i32, b: i32, c: i32) -> i32 {
834     a + b + c
835 }
836 "#,
837         );
838     }
839
840     #[test]
841     fn supports_fn_in_mods() {
842         check_assist(
843             generate_doc_example,
844             r#"
845 pub mod a {
846     pub mod b {
847         ///$0
848         pub fn noop() {}
849     }
850 }
851 "#,
852             r#"
853 pub mod a {
854     pub mod b {
855         ///
856         ///
857         /// # Examples
858         ///
859         /// ```
860         /// use test::a::b::noop;
861         ///
862         /// noop();
863         /// ```
864         pub fn noop() {}
865     }
866 }
867 "#,
868         );
869     }
870
871     #[test]
872     fn supports_fn_in_impl() {
873         check_assist(
874             generate_doc_example,
875             r#"
876 pub struct MyStruct;
877 impl MyStruct {
878     ///$0
879     pub fn noop() {}
880 }
881 "#,
882             r#"
883 pub struct MyStruct;
884 impl MyStruct {
885     ///
886     ///
887     /// # Examples
888     ///
889     /// ```
890     /// use test::MyStruct;
891     ///
892     /// MyStruct::noop();
893     /// ```
894     pub fn noop() {}
895 }
896 "#,
897         );
898     }
899
900     #[test]
901     fn supports_unsafe_fn_in_trait() {
902         check_assist(
903             generate_documentation_template,
904             r#"
905 pub trait MyTrait {
906     unsafe fn unsafe_funct$0ion_trait();
907 }
908 "#,
909             r#"
910 pub trait MyTrait {
911     /// .
912     ///
913     /// # Safety
914     ///
915     /// .
916     unsafe fn unsafe_function_trait();
917 }
918 "#,
919         );
920     }
921
922     #[test]
923     fn supports_fn_in_trait_with_default_panicking() {
924         check_assist(
925             generate_documentation_template,
926             r#"
927 pub trait MyTrait {
928     fn function_trait_with_$0default_panicking() {
929         panic!()
930     }
931 }
932 "#,
933             r#"
934 pub trait MyTrait {
935     /// .
936     ///
937     /// # Panics
938     ///
939     /// Panics if .
940     fn function_trait_with_default_panicking() {
941         panic!()
942     }
943 }
944 "#,
945         );
946     }
947
948     #[test]
949     fn supports_fn_in_trait_returning_result() {
950         check_assist(
951             generate_documentation_template,
952             r#"
953 pub trait MyTrait {
954     fn function_tr$0ait_returning_result() -> Result<(), std::io::Error>;
955 }
956 "#,
957             r#"
958 pub trait MyTrait {
959     /// .
960     ///
961     /// # Errors
962     ///
963     /// This function will return an error if .
964     fn function_trait_returning_result() -> Result<(), std::io::Error>;
965 }
966 "#,
967         );
968     }
969
970     #[test]
971     fn detects_new() {
972         check_assist(
973             generate_documentation_template,
974             r#"
975 pub struct String(u8);
976 impl String {
977     pub fn new$0(x: u8) -> String {
978         String(x)
979     }
980 }
981 "#,
982             r#"
983 pub struct String(u8);
984 impl String {
985     /// Creates a new [`String`].
986     pub fn new(x: u8) -> String {
987         String(x)
988     }
989 }
990 "#,
991         );
992         check_assist(
993             generate_documentation_template,
994             r#"
995 #[derive(Debug, PartialEq)]
996 pub struct MyGenericStruct<T> {
997     pub x: T,
998 }
999 impl<T> MyGenericStruct<T> {
1000     pub fn new$0(x: T) -> MyGenericStruct<T> {
1001         MyGenericStruct { x }
1002     }
1003 }
1004 "#,
1005             r#"
1006 #[derive(Debug, PartialEq)]
1007 pub struct MyGenericStruct<T> {
1008     pub x: T,
1009 }
1010 impl<T> MyGenericStruct<T> {
1011     /// Creates a new [`MyGenericStruct<T>`].
1012     pub fn new(x: T) -> MyGenericStruct<T> {
1013         MyGenericStruct { x }
1014     }
1015 }
1016 "#,
1017         );
1018     }
1019
1020     #[test]
1021     fn removes_one_lifetime_from_description() {
1022         check_assist(
1023             generate_documentation_template,
1024             r#"
1025 #[derive(Debug, PartialEq)]
1026 pub struct MyGenericStruct<'a, T> {
1027     pub x: &'a T,
1028 }
1029 impl<'a, T> MyGenericStruct<'a, T> {
1030     pub fn new$0(x: &'a T) -> Self {
1031         MyGenericStruct { x }
1032     }
1033 }
1034 "#,
1035             r#"
1036 #[derive(Debug, PartialEq)]
1037 pub struct MyGenericStruct<'a, T> {
1038     pub x: &'a T,
1039 }
1040 impl<'a, T> MyGenericStruct<'a, T> {
1041     /// Creates a new [`MyGenericStruct<T>`].
1042     pub fn new(x: &'a T) -> Self {
1043         MyGenericStruct { x }
1044     }
1045 }
1046 "#,
1047         );
1048     }
1049
1050     #[test]
1051     fn removes_all_lifetimes_from_description() {
1052         check_assist(
1053             generate_documentation_template,
1054             r#"
1055 #[derive(Debug, PartialEq)]
1056 pub struct MyGenericStruct<'a, 'b, T> {
1057     pub x: &'a T,
1058     pub y: &'b T,
1059 }
1060 impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
1061     pub fn new$0(x: &'a T, y: &'b T) -> Self {
1062         MyGenericStruct { x, y }
1063     }
1064 }
1065 "#,
1066             r#"
1067 #[derive(Debug, PartialEq)]
1068 pub struct MyGenericStruct<'a, 'b, T> {
1069     pub x: &'a T,
1070     pub y: &'b T,
1071 }
1072 impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
1073     /// Creates a new [`MyGenericStruct<T>`].
1074     pub fn new(x: &'a T, y: &'b T) -> Self {
1075         MyGenericStruct { x, y }
1076     }
1077 }
1078 "#,
1079         );
1080     }
1081
1082     #[test]
1083     fn removes_all_lifetimes_and_brackets_from_description() {
1084         check_assist(
1085             generate_documentation_template,
1086             r#"
1087 #[derive(Debug, PartialEq)]
1088 pub struct MyGenericStruct<'a, 'b> {
1089     pub x: &'a usize,
1090     pub y: &'b usize,
1091 }
1092 impl<'a, 'b> MyGenericStruct<'a, 'b> {
1093     pub fn new$0(x: &'a usize, y: &'b usize) -> Self {
1094         MyGenericStruct { x, y }
1095     }
1096 }
1097 "#,
1098             r#"
1099 #[derive(Debug, PartialEq)]
1100 pub struct MyGenericStruct<'a, 'b> {
1101     pub x: &'a usize,
1102     pub y: &'b usize,
1103 }
1104 impl<'a, 'b> MyGenericStruct<'a, 'b> {
1105     /// Creates a new [`MyGenericStruct`].
1106     pub fn new(x: &'a usize, y: &'b usize) -> Self {
1107         MyGenericStruct { x, y }
1108     }
1109 }
1110 "#,
1111         );
1112     }
1113
1114     #[test]
1115     fn detects_new_with_self() {
1116         check_assist(
1117             generate_documentation_template,
1118             r#"
1119 #[derive(Debug, PartialEq)]
1120 pub struct MyGenericStruct2<T> {
1121     pub x: T,
1122 }
1123 impl<T> MyGenericStruct2<T> {
1124     pub fn new$0(x: T) -> Self {
1125         MyGenericStruct2 { x }
1126     }
1127 }
1128 "#,
1129             r#"
1130 #[derive(Debug, PartialEq)]
1131 pub struct MyGenericStruct2<T> {
1132     pub x: T,
1133 }
1134 impl<T> MyGenericStruct2<T> {
1135     /// Creates a new [`MyGenericStruct2<T>`].
1136     pub fn new(x: T) -> Self {
1137         MyGenericStruct2 { x }
1138     }
1139 }
1140 "#,
1141         );
1142     }
1143
1144     #[test]
1145     fn supports_method_call() {
1146         check_assist(
1147             generate_doc_example,
1148             r#"
1149 impl<T> MyGenericStruct<T> {
1150     ///$0
1151     pub fn consume(self) {}
1152 }
1153 "#,
1154             r#"
1155 impl<T> MyGenericStruct<T> {
1156     ///
1157     ///
1158     /// # Examples
1159     ///
1160     /// ```
1161     /// use test::MyGenericStruct;
1162     ///
1163     /// let my_generic_struct = ;
1164     /// my_generic_struct.consume();
1165     /// ```
1166     pub fn consume(self) {}
1167 }
1168 "#,
1169         );
1170     }
1171
1172     #[test]
1173     fn checks_modified_self_param() {
1174         check_assist(
1175             generate_doc_example,
1176             r#"
1177 impl<T> MyGenericStruct<T> {
1178     ///$0
1179     pub fn modify(&mut self, new_value: T) {
1180         self.x = new_value;
1181     }
1182 }
1183 "#,
1184             r#"
1185 impl<T> MyGenericStruct<T> {
1186     ///
1187     ///
1188     /// # Examples
1189     ///
1190     /// ```
1191     /// use test::MyGenericStruct;
1192     ///
1193     /// let mut my_generic_struct = ;
1194     /// my_generic_struct.modify(new_value);
1195     /// assert_eq!(my_generic_struct, );
1196     /// ```
1197     pub fn modify(&mut self, new_value: T) {
1198         self.x = new_value;
1199     }
1200 }
1201 "#,
1202         );
1203     }
1204
1205     #[test]
1206     fn generates_intro_for_getters() {
1207         check_assist(
1208             generate_documentation_template,
1209             r#"
1210 pub struct S;
1211 impl S {
1212     pub fn speed$0(&self) -> f32 { 0.0 }
1213 }
1214 "#,
1215             r#"
1216 pub struct S;
1217 impl S {
1218     /// Returns the speed of this [`S`].
1219     pub fn speed(&self) -> f32 { 0.0 }
1220 }
1221 "#,
1222         );
1223         check_assist(
1224             generate_documentation_template,
1225             r#"
1226 pub struct S;
1227 impl S {
1228     pub fn data$0(&self) -> &[u8] { &[] }
1229 }
1230 "#,
1231             r#"
1232 pub struct S;
1233 impl S {
1234     /// Returns a reference to the data of this [`S`].
1235     pub fn data(&self) -> &[u8] { &[] }
1236 }
1237 "#,
1238         );
1239         check_assist(
1240             generate_documentation_template,
1241             r#"
1242 pub struct S;
1243 impl S {
1244     pub fn data$0(&mut self) -> &mut [u8] { &mut [] }
1245 }
1246 "#,
1247             r#"
1248 pub struct S;
1249 impl S {
1250     /// Returns a mutable reference to the data of this [`S`].
1251     pub fn data(&mut self) -> &mut [u8] { &mut [] }
1252 }
1253 "#,
1254         );
1255         check_assist(
1256             generate_documentation_template,
1257             r#"
1258 pub struct S;
1259 impl S {
1260     pub fn data_mut$0(&mut self) -> &mut [u8] { &mut [] }
1261 }
1262 "#,
1263             r#"
1264 pub struct S;
1265 impl S {
1266     /// Returns a mutable reference to the data of this [`S`].
1267     pub fn data_mut(&mut self) -> &mut [u8] { &mut [] }
1268 }
1269 "#,
1270         );
1271     }
1272
1273     #[test]
1274     fn no_getter_intro_for_prefixed_methods() {
1275         check_assist(
1276             generate_documentation_template,
1277             r#"
1278 pub struct S;
1279 impl S {
1280     pub fn as_bytes$0(&self) -> &[u8] { &[] }
1281 }
1282 "#,
1283             r#"
1284 pub struct S;
1285 impl S {
1286     /// .
1287     pub fn as_bytes(&self) -> &[u8] { &[] }
1288 }
1289 "#,
1290         );
1291     }
1292
1293     #[test]
1294     fn generates_intro_for_setters() {
1295         check_assist(
1296             generate_documentation_template,
1297             r#"
1298 pub struct S;
1299 impl S {
1300     pub fn set_data$0(&mut self, data: Vec<u8>) {}
1301 }
1302 "#,
1303             r#"
1304 pub struct S;
1305 impl S {
1306     /// Sets the data of this [`S`].
1307     pub fn set_data(&mut self, data: Vec<u8>) {}
1308 }
1309 "#,
1310         );
1311         check_assist(
1312             generate_documentation_template,
1313             r#"
1314 pub struct S;
1315 impl S {
1316     pub fn set_domain_name$0(&mut self, name: String) {}
1317 }
1318 "#,
1319             r#"
1320 pub struct S;
1321 impl S {
1322     /// Sets the domain name of this [`S`].
1323     pub fn set_domain_name(&mut self, name: String) {}
1324 }
1325 "#,
1326         );
1327     }
1328 }