Unnamed repository; edit this file 'description' to name the repository.
Improve docs generation assist
Jonas Schievink 2022-05-18
parent 76030eb · commit 93b62db
-rw-r--r--crates/ide-assists/src/handlers/generate_documentation_template.rs561
-rw-r--r--crates/ide-assists/src/lib.rs1
-rw-r--r--crates/ide-assists/src/tests/generated.rs53
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs4
4 files changed, 248 insertions, 371 deletions
diff --git a/crates/ide-assists/src/handlers/generate_documentation_template.rs b/crates/ide-assists/src/handlers/generate_documentation_template.rs
index 7864ca2a4e..74c71f13ee 100644
--- a/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -1,10 +1,11 @@
use hir::{AsAssocItem, HasVisibility, ModuleDef, Visibility};
use ide_db::assists::{AssistId, AssistKind};
use itertools::Itertools;
-use stdx::to_lower_snake_case;
+use stdx::{format_to, to_lower_snake_case};
use syntax::{
+ algo::skip_whitespace_token,
ast::{self, edit::IndentLevel, HasDocComments, HasName},
- AstNode,
+ match_ast, AstNode, AstToken,
};
use crate::assist_context::{AssistContext, Assists};
@@ -14,27 +15,29 @@ use crate::assist_context::{AssistContext, Assists};
// Adds a documentation template above a function definition / declaration.
//
// ```
-// pub fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
-// unimplemented!()
+// pub struct S;
+// impl S {
+// pub unsafe fn set_len$0(&mut self, len: usize) -> Result<(), std::io::Error> {
+// /* ... */
+// }
// }
// ```
// ->
// ```
-// /// .
-// ///
-// /// # Examples
-// ///
-// /// ```
-// /// use test::my_func;
-// ///
-// /// assert_eq!(my_func(a, b), );
-// /// ```
-// ///
-// /// # Errors
-// ///
-// /// This function will return an error if .
-// pub fn my_func(a: i32, b: i32) -> Result<(), std::io::Error> {
-// unimplemented!()
+// pub struct S;
+// impl S {
+// /// Sets the length.
+// ///
+// /// # Errors
+// ///
+// /// This function will return an error if .
+// ///
+// /// # Safety
+// ///
+// /// .
+// pub unsafe fn set_len(&mut self, len: usize) -> Result<(), std::io::Error> {
+// /* ... */
+// }
// }
// ```
pub(crate) fn generate_documentation_template(
@@ -43,10 +46,7 @@ pub(crate) fn generate_documentation_template(
) -> Option<()> {
let name = ctx.find_node_at_offset::<ast::Name>()?;
let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;
- if is_in_trait_impl(&ast_func, ctx)
- || !is_public(&ast_func, ctx)?
- || ast_func.doc_comments().next().is_some()
- {
+ if is_in_trait_impl(&ast_func, ctx) || ast_func.doc_comments().next().is_some() {
return None;
}
@@ -62,10 +62,6 @@ pub(crate) fn generate_documentation_template(
// Introduction / short function description before the sections
let mut doc_lines = vec![introduction_builder(&ast_func, ctx).unwrap_or(".".into())];
// Then come the sections
- if let Some(mut lines) = examples_builder(&ast_func, ctx) {
- doc_lines.push("".into());
- doc_lines.append(&mut lines);
- }
for section_builder in [panics_builder, errors_builder, safety_builder] {
if let Some(mut lines) = section_builder(&ast_func) {
doc_lines.push("".into());
@@ -77,7 +73,109 @@ pub(crate) fn generate_documentation_template(
)
}
-/// Builds an introduction, trying to be smart if the function is `::new()`
+// Assist: generate_doc_example
+//
+// Generates a rustdoc example when editing an item's documentation.
+//
+// ```
+// /// Adds two numbers.$0
+// pub fn add(a: i32, b: i32) -> i32 { a + b }
+// ```
+// ->
+// ```
+// /// Adds two numbers.
+// ///
+// /// # Examples
+// ///
+// /// ```
+// /// use test::add;
+// ///
+// /// assert_eq!(add(a, b), );
+// /// ```
+// pub fn add(a: i32, b: i32) -> i32 { a + b }
+// ```
+pub(crate) fn generate_doc_example(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+ let tok: ast::Comment = ctx.find_token_at_offset()?;
+ let node = tok.syntax().parent()?;
+ let last_doc_token =
+ ast::AnyHasDocComments::cast(node.clone())?.doc_comments().last()?.syntax().clone();
+ let next_token = skip_whitespace_token(last_doc_token.next_token()?, syntax::Direction::Next)?;
+
+ let example = match_ast! {
+ match node {
+ ast::Fn(it) => make_example_for_fn(&it, ctx)?,
+ _ => return None,
+ }
+ };
+
+ let mut lines = string_vec_from(&["", "# Examples", "", "```"]);
+ lines.extend(example.lines().map(String::from));
+ lines.push("```".into());
+ let indent_level = IndentLevel::from_node(&node);
+
+ acc.add(
+ AssistId("generate_doc_example", AssistKind::Generate),
+ "Generate a documentation example",
+ node.text_range(),
+ |builder| {
+ builder.insert(
+ next_token.text_range().start(),
+ documentation_from_lines(lines, indent_level),
+ );
+ },
+ )
+}
+
+fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<String> {
+ if !is_public(ast_func, ctx)? {
+ // Doctests for private items can't actually name the item, so they're pretty useless.
+ return None;
+ }
+
+ if is_in_trait_def(ast_func, ctx) {
+ // This is not yet implemented.
+ return None;
+ }
+
+ let mut example = String::new();
+
+ let is_unsafe = ast_func.unsafe_token().is_some();
+ let param_list = ast_func.param_list()?;
+ let ref_mut_params = ref_mut_params(&param_list);
+ let self_name = self_name(ast_func);
+
+ format_to!(example, "use {};\n\n", build_path(ast_func, ctx)?);
+ if let Some(self_name) = &self_name {
+ if let Some(mtbl) = is_ref_mut_self(ast_func) {
+ let mtbl = if mtbl == true { " mut" } else { "" };
+ format_to!(example, "let{} {} = ;\n", mtbl, self_name);
+ }
+ }
+ for param_name in &ref_mut_params {
+ format_to!(example, "let mut {} = ;\n", param_name);
+ }
+ // Call the function, check result
+ let function_call = function_call(ast_func, &param_list, self_name.as_deref(), is_unsafe)?;
+ if returns_a_value(ast_func, ctx) {
+ if count_parameters(&param_list) < 3 {
+ format_to!(example, "assert_eq!({}, );\n", function_call);
+ } else {
+ format_to!(example, "let result = {};\n", function_call);
+ example.push_str("assert_eq!(result, );\n");
+ }
+ } else {
+ format_to!(example, "{};\n", function_call);
+ }
+ // Check the mutated values
+ if is_ref_mut_self(ast_func) == Some(true) {
+ format_to!(example, "assert_eq!({}, );", self_name?);
+ }
+ for param_name in &ref_mut_params {
+ format_to!(example, "assert_eq!({}, );", param_name);
+ }
+ Some(example)
+}
+
fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<String> {
let hir_func = ctx.sema.to_def(ast_func)?;
let container = hir_func.as_assoc_item(ctx.db())?.container(ctx.db());
@@ -103,7 +201,10 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<Strin
if name.starts_with("as_") || name.starts_with("to_") || name == "get" {
return None;
}
- let what = name.trim_end_matches("_mut").replace('_', " ");
+ let mut what = name.trim_end_matches("_mut").replace('_', " ");
+ if what == "len" {
+ what = "length".into()
+ };
let reference = if ret_ty.is_mutable_reference() {
" a mutable reference to"
} else if ret_ty.is_reference() {
@@ -121,7 +222,10 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<Strin
return None;
}
- let what = name.trim_start_matches("set_").replace('_', " ");
+ let mut what = name.trim_start_matches("set_").replace('_', " ");
+ if what == "len" {
+ what = "length".into()
+ };
Some(format!("Sets the {what}."))
};
@@ -138,19 +242,6 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<Strin
None
}
-/// Builds an `# Examples` section. An option is returned to be able to manage an error in the AST.
-fn examples_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<Vec<String>> {
- let mut lines = string_vec_from(&["# Examples", "", "```"]);
- if is_in_trait_def(ast_func, ctx) {
- lines.push("// Example template not implemented for trait functions".into());
- } else {
- lines.append(&mut gen_ex_template(ast_func, ctx)?)
- };
-
- lines.push("```".into());
- Some(lines)
-}
-
/// Builds an optional `# Panics` section
fn panics_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
match can_panic(ast_func) {
@@ -176,44 +267,6 @@ fn safety_builder(ast_func: &ast::Fn) -> Option<Vec<String>> {
}
}
-/// Generates an example template
-fn gen_ex_template(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<Vec<String>> {
- let mut lines = Vec::new();
- let is_unsafe = ast_func.unsafe_token().is_some();
- let param_list = ast_func.param_list()?;
- let ref_mut_params = ref_mut_params(&param_list);
- let self_name: Option<String> = self_name(ast_func);
-
- lines.push(format!("use {};", build_path(ast_func, ctx)?));
- lines.push("".into());
- if let Some(self_definition) = self_definition(ast_func, self_name.as_deref()) {
- lines.push(self_definition);
- }
- for param_name in &ref_mut_params {
- lines.push(format!("let mut {} = ;", param_name))
- }
- // Call the function, check result
- let function_call = function_call(ast_func, &param_list, self_name.as_deref(), is_unsafe)?;
- if returns_a_value(ast_func, ctx) {
- if count_parameters(&param_list) < 3 {
- lines.push(format!("assert_eq!({}, );", function_call));
- } else {
- lines.push(format!("let result = {};", function_call));
- lines.push("assert_eq!(result, );".into());
- }
- } else {
- lines.push(format!("{};", function_call));
- }
- // Check the mutated values
- if is_ref_mut_self(ast_func) == Some(true) {
- lines.push(format!("assert_eq!({}, );", self_name?));
- }
- for param_name in &ref_mut_params {
- lines.push(format!("assert_eq!({}, );", param_name));
- }
- Some(lines)
-}
-
/// Checks if the function is public / exported
fn is_public(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<bool> {
let hir_func = ctx.sema.to_def(ast_func)?;
@@ -319,15 +372,6 @@ fn is_ref_mut_self(ast_func: &ast::Fn) -> Option<bool> {
Some(self_param.mut_token().is_some() && self_param.amp_token().is_some())
}
-/// Helper function to define an variable to be the `self` argument
-fn self_definition(ast_func: &ast::Fn, self_name: Option<&str>) -> Option<String> {
- let definition = match is_ref_mut_self(ast_func)? {
- true => format!("let mut {} = ;", self_name?),
- false => format!("let {} = ;", self_name?),
- };
- Some(definition)
-}
-
/// Helper function to determine if a parameter is `&mut`
fn is_a_ref_mut_param(param: &ast::Param) -> bool {
match param.ty() {
@@ -476,70 +520,62 @@ impl MyTrait for MyStruct {
}
#[test]
- fn not_applicable_if_function_is_private() {
- check_assist_not_applicable(generate_documentation_template, r#"fn priv$0ate() {}"#);
- }
-
- #[test]
- fn not_applicable_if_function_is_pub_crate() {
- check_assist_not_applicable(
- generate_documentation_template,
- r#"pub(crate) fn pri$0vate() {}"#,
- );
- }
-
- #[test]
- fn not_applicable_if_function_is_in_private_mod() {
+ fn not_applicable_if_function_already_documented() {
check_assist_not_applicable(
generate_documentation_template,
r#"
-mod PrivateModule {
- pub fn pri$0vate() {}
-}"#,
+/// Some documentation here
+pub fn $0documented_function() {}
+"#,
);
}
#[test]
- fn not_applicable_if_function_is_in_pub_crate_mod() {
- check_assist_not_applicable(
+ fn supports_noop_function() {
+ check_assist(
generate_documentation_template,
r#"
-pub(crate) mod PrivateModule {
- pub fn pr$0ivate() {}
-}"#,
+pub fn no$0op() {}
+"#,
+ r#"
+/// .
+pub fn noop() {}
+"#,
);
}
#[test]
- fn not_applicable_if_function_is_in_non_public_mod_is_recursive() {
- check_assist_not_applicable(
+ fn is_applicable_if_function_is_private() {
+ check_assist(
generate_documentation_template,
r#"
-mod ParentPrivateModule {
- pub mod PrivateModule {
- pub fn pr$0ivate() {}
- }
-}"#,
+fn priv$0ate() {}
+"#,
+ r#"
+/// .
+fn private() {}
+"#,
);
}
#[test]
- fn not_applicable_if_function_already_documented() {
+ fn no_doc_example_for_private_fn() {
check_assist_not_applicable(
- generate_documentation_template,
+ generate_doc_example,
r#"
-/// Some documentation here
-pub fn $0documented_function() {}
+///$0
+fn private() {}
"#,
);
}
#[test]
- fn supports_noop_function() {
+ fn supports_a_parameter() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
-pub fn no$0op() {}
+/// $0.
+pub fn noop_with_param(_a: i32) {}
"#,
r#"
/// .
@@ -547,47 +583,48 @@ pub fn no$0op() {}
/// # Examples
///
/// ```
-/// use test::noop;
+/// use test::noop_with_param;
///
-/// noop();
+/// noop_with_param(_a);
/// ```
-pub fn noop() {}
+pub fn noop_with_param(_a: i32) {}
"#,
);
}
#[test]
- fn supports_a_parameter() {
+ fn detects_unsafe_function() {
check_assist(
generate_documentation_template,
r#"
-pub fn no$0op_with_param(_a: i32) {}
+pub unsafe fn no$0op_unsafe() {}
"#,
r#"
/// .
///
-/// # Examples
-///
-/// ```
-/// use test::noop_with_param;
+/// # Safety
///
-/// noop_with_param(_a);
-/// ```
-pub fn noop_with_param(_a: i32) {}
+/// .
+pub unsafe fn noop_unsafe() {}
"#,
);
- }
-
- #[test]
- fn detects_unsafe_function() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
-pub unsafe fn no$0op_unsafe() {}
+/// .
+///
+/// # Safety$0
+///
+/// .
+pub unsafe fn noop_unsafe() {}
"#,
r#"
/// .
///
+/// # Safety
+///
+/// .
+///
/// # Examples
///
/// ```
@@ -595,10 +632,6 @@ pub unsafe fn no$0op_unsafe() {}
///
/// unsafe { noop_unsafe() };
/// ```
-///
-/// # Safety
-///
-/// .
pub unsafe fn noop_unsafe() {}
"#,
);
@@ -618,14 +651,6 @@ pub fn panic$0s_if(a: bool) {
r#"
/// .
///
-/// # Examples
-///
-/// ```
-/// use test::panics_if;
-///
-/// panics_if(a);
-/// ```
-///
/// # Panics
///
/// Panics if .
@@ -650,14 +675,6 @@ pub fn $0panics_if_not(a: bool) {
r#"
/// .
///
-/// # Examples
-///
-/// ```
-/// use test::panics_if_not;
-///
-/// panics_if_not(a);
-/// ```
-///
/// # Panics
///
/// Panics if .
@@ -680,14 +697,6 @@ pub fn $0panics_if_none(a: Option<()>) {
r#"
/// .
///
-/// # Examples
-///
-/// ```
-/// use test::panics_if_none;
-///
-/// panics_if_none(a);
-/// ```
-///
/// # Panics
///
/// Panics if .
@@ -710,14 +719,6 @@ pub fn $0panics_if_none2(a: Option<()>) {
r#"
/// .
///
-/// # Examples
-///
-/// ```
-/// use test::panics_if_none2;
-///
-/// panics_if_none2(a);
-/// ```
-///
/// # Panics
///
/// Panics if .
@@ -731,14 +732,15 @@ pub fn panics_if_none2(a: Option<()>) {
#[test]
fn checks_output_in_example() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
+///$0
pub fn returns_a_value$0() -> i32 {
0
}
"#,
r#"
-/// .
+///
///
/// # Examples
///
@@ -766,14 +768,6 @@ pub fn returns_a_result$0() -> Result<i32, std::io::Error> {
r#"
/// .
///
-/// # Examples
-///
-/// ```
-/// use test::returns_a_result;
-///
-/// assert_eq!(returns_a_result(), );
-/// ```
-///
/// # Errors
///
/// This function will return an error if .
@@ -787,14 +781,15 @@ pub fn returns_a_result() -> Result<i32, std::io::Error> {
#[test]
fn checks_ref_mut_in_example() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
+///$0
pub fn modifies_a_value$0(a: &mut i32) {
*a = 0;
}
"#,
r#"
-/// .
+///
///
/// # Examples
///
@@ -815,14 +810,15 @@ pub fn modifies_a_value(a: &mut i32) {
#[test]
fn stores_result_if_at_least_3_params() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
+///$0
pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
a + b + c
}
"#,
r#"
-/// .
+///
///
/// # Examples
///
@@ -842,18 +838,19 @@ pub fn sum3(a: i32, b: i32, c: i32) -> i32 {
#[test]
fn supports_fn_in_mods() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
pub mod a {
pub mod b {
- pub fn no$0op() {}
+ ///$0
+ pub fn noop() {}
}
}
"#,
r#"
pub mod a {
pub mod b {
- /// .
+ ///
///
/// # Examples
///
@@ -872,17 +869,18 @@ pub mod a {
#[test]
fn supports_fn_in_impl() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
pub struct MyStruct;
impl MyStruct {
- pub fn no$0op() {}
+ ///$0
+ pub fn noop() {}
}
"#,
r#"
pub struct MyStruct;
impl MyStruct {
- /// .
+ ///
///
/// # Examples
///
@@ -898,30 +896,6 @@ impl MyStruct {
}
#[test]
- fn supports_fn_in_trait() {
- check_assist(
- generate_documentation_template,
- r#"
-pub trait MyTrait {
- fn fun$0ction_trait();
-}
-"#,
- r#"
-pub trait MyTrait {
- /// .
- ///
- /// # Examples
- ///
- /// ```
- /// // Example template not implemented for trait functions
- /// ```
- fn function_trait();
-}
-"#,
- );
- }
-
- #[test]
fn supports_unsafe_fn_in_trait() {
check_assist(
generate_documentation_template,
@@ -934,12 +908,6 @@ pub trait MyTrait {
pub trait MyTrait {
/// .
///
- /// # Examples
- ///
- /// ```
- /// // Example template not implemented for trait functions
- /// ```
- ///
/// # Safety
///
/// .
@@ -964,12 +932,6 @@ pub trait MyTrait {
pub trait MyTrait {
/// .
///
- /// # Examples
- ///
- /// ```
- /// // Example template not implemented for trait functions
- /// ```
- ///
/// # Panics
///
/// Panics if .
@@ -994,12 +956,6 @@ pub trait MyTrait {
pub trait MyTrait {
/// .
///
- /// # Examples
- ///
- /// ```
- /// // Example template not implemented for trait functions
- /// ```
- ///
/// # Errors
///
/// This function will return an error if .
@@ -1031,14 +987,6 @@ pub struct MyGenericStruct<T> {
}
impl<T> MyGenericStruct<T> {
/// Creates a new [`MyGenericStruct<T>`].
- ///
- /// # Examples
- ///
- /// ```
- /// use test::MyGenericStruct;
- ///
- /// assert_eq!(MyGenericStruct::new(x), );
- /// ```
pub fn new(x: T) -> MyGenericStruct<T> {
MyGenericStruct { x }
}
@@ -1069,14 +1017,6 @@ pub struct MyGenericStruct<'a, T> {
}
impl<'a, T> MyGenericStruct<'a, T> {
/// Creates a new [`MyGenericStruct<T>`].
- ///
- /// # Examples
- ///
- /// ```
- /// use test::MyGenericStruct;
- ///
- /// assert_eq!(MyGenericStruct::new(x), );
- /// ```
pub fn new(x: &'a T) -> Self {
MyGenericStruct { x }
}
@@ -1109,14 +1049,6 @@ pub struct MyGenericStruct<'a, 'b, T> {
}
impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
/// Creates a new [`MyGenericStruct<T>`].
- ///
- /// # Examples
- ///
- /// ```
- /// use test::MyGenericStruct;
- ///
- /// assert_eq!(MyGenericStruct::new(x, y), );
- /// ```
pub fn new(x: &'a T, y: &'b T) -> Self {
MyGenericStruct { x, y }
}
@@ -1149,14 +1081,6 @@ pub struct MyGenericStruct<'a, 'b> {
}
impl<'a, 'b> MyGenericStruct<'a, 'b> {
/// Creates a new [`MyGenericStruct`].
- ///
- /// # Examples
- ///
- /// ```
- /// use test::MyGenericStruct;
- ///
- /// assert_eq!(MyGenericStruct::new(x, y), );
- /// ```
pub fn new(x: &'a usize, y: &'b usize) -> Self {
MyGenericStruct { x, y }
}
@@ -1187,14 +1111,6 @@ pub struct MyGenericStruct2<T> {
}
impl<T> MyGenericStruct2<T> {
/// Creates a new [`MyGenericStruct2<T>`].
- ///
- /// # Examples
- ///
- /// ```
- /// use test::MyGenericStruct2;
- ///
- /// assert_eq!(MyGenericStruct2::new(x), );
- /// ```
pub fn new(x: T) -> Self {
MyGenericStruct2 { x }
}
@@ -1206,15 +1122,16 @@ impl<T> MyGenericStruct2<T> {
#[test]
fn supports_method_call() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
impl<T> MyGenericStruct<T> {
- pub fn co$0nsume(self) {}
+ ///$0
+ pub fn consume(self) {}
}
"#,
r#"
impl<T> MyGenericStruct<T> {
- /// .
+ ///
///
/// # Examples
///
@@ -1233,17 +1150,18 @@ impl<T> MyGenericStruct<T> {
#[test]
fn checks_modified_self_param() {
check_assist(
- generate_documentation_template,
+ generate_doc_example,
r#"
impl<T> MyGenericStruct<T> {
- pub fn modi$0fy(&mut self, new_value: T) {
+ ///$0
+ pub fn modify(&mut self, new_value: T) {
self.x = new_value;
}
}
"#,
r#"
impl<T> MyGenericStruct<T> {
- /// .
+ ///
///
/// # Examples
///
@@ -1276,15 +1194,6 @@ impl S {
pub struct S;
impl S {
/// Returns the speed.
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let s = ;
- /// assert_eq!(s.speed(), );
- /// ```
pub fn speed(&self) -> f32 { 0.0 }
}
"#,
@@ -1301,15 +1210,6 @@ impl S {
pub struct S;
impl S {
/// Returns a reference to the data.
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let s = ;
- /// assert_eq!(s.data(), );
- /// ```
pub fn data(&self) -> &[u8] { &[] }
}
"#,
@@ -1326,16 +1226,6 @@ impl S {
pub struct S;
impl S {
/// Returns a mutable reference to the data.
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let mut s = ;
- /// assert_eq!(s.data(), );
- /// assert_eq!(s, );
- /// ```
pub fn data(&mut self) -> &mut [u8] { &mut [] }
}
"#,
@@ -1352,16 +1242,6 @@ impl S {
pub struct S;
impl S {
/// Returns a mutable reference to the data.
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let mut s = ;
- /// assert_eq!(s.data_mut(), );
- /// assert_eq!(s, );
- /// ```
pub fn data_mut(&mut self) -> &mut [u8] { &mut [] }
}
"#,
@@ -1382,15 +1262,6 @@ impl S {
pub struct S;
impl S {
/// .
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let s = ;
- /// assert_eq!(s.as_bytes(), );
- /// ```
pub fn as_bytes(&self) -> &[u8] { &[] }
}
"#,
@@ -1411,16 +1282,6 @@ impl S {
pub struct S;
impl S {
/// Sets the data.
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let mut s = ;
- /// s.set_data(data);
- /// assert_eq!(s, );
- /// ```
pub fn set_data(&mut self, data: Vec<u8>) {}
}
"#,
@@ -1437,16 +1298,6 @@ impl S {
pub struct S;
impl S {
/// Sets the domain name.
- ///
- /// # Examples
- ///
- /// ```
- /// use test::S;
- ///
- /// let mut s = ;
- /// s.set_domain_name(name);
- /// assert_eq!(s, );
- /// ```
pub fn set_domain_name(&mut self, name: String) {}
}
"#,
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index a5dfb5d295..f78dbf2ab8 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -223,6 +223,7 @@ mod handlers {
generate_default_from_enum_variant::generate_default_from_enum_variant,
generate_default_from_new::generate_default_from_new,
generate_documentation_template::generate_documentation_template,
+ generate_documentation_template::generate_doc_example,
generate_enum_is_method::generate_enum_is_method,
generate_enum_projection_method::generate_enum_as_method,
generate_enum_projection_method::generate_enum_try_into_method,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 7772563b83..0da4197afe 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -863,30 +863,55 @@ impl core::ops::Deref for B {
}
#[test]
-fn doctest_generate_documentation_template() {
+fn doctest_generate_doc_example() {
check_doc_test(
- "generate_documentation_template",
+ "generate_doc_example",
r#####"
-pub fn my_$0func(a: i32, b: i32) -> Result<(), std::io::Error> {
- unimplemented!()
-}
+/// Adds two numbers.$0
+pub fn add(a: i32, b: i32) -> i32 { a + b }
"#####,
r#####"
-/// .
+/// Adds two numbers.
///
/// # Examples
///
/// ```
-/// use test::my_func;
+/// use test::add;
///
-/// assert_eq!(my_func(a, b), );
+/// assert_eq!(add(a, b), );
/// ```
-///
-/// # Errors
-///
-/// This function will return an error if .
-pub fn my_func(a: i32, b: i32) -> Result<(), std::io::Error> {
- unimplemented!()
+pub fn add(a: i32, b: i32) -> i32 { a + b }
+"#####,
+ )
+}
+
+#[test]
+fn doctest_generate_documentation_template() {
+ check_doc_test(
+ "generate_documentation_template",
+ r#####"
+pub struct S;
+impl S {
+ pub unsafe fn set_len$0(&mut self, len: usize) -> Result<(), std::io::Error> {
+ /* ... */
+ }
+}
+"#####,
+ r#####"
+pub struct S;
+impl S {
+ /// Sets the length.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if .
+ ///
+ /// # Safety
+ ///
+ /// .
+ pub unsafe fn set_len(&mut self, len: usize) -> Result<(), std::io::Error> {
+ /* ... */
+ }
}
"#####,
)
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 143b63e11c..5bb925f62b 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -494,7 +494,7 @@ fn main() {}
server.request::<CodeActionRequest>(
CodeActionParams {
text_document: server.doc_id("src/lib.rs"),
- range: Range::new(Position::new(2, 4), Position::new(2, 7)),
+ range: Range::new(Position::new(2, 8), Position::new(2, 8)),
context: CodeActionContext::default(),
partial_result_params: PartialResultParams::default(),
work_done_progress_params: WorkDoneProgressParams::default(),
@@ -578,7 +578,7 @@ fn main() {{}}
server.request::<CodeActionRequest>(
CodeActionParams {
text_document: server.doc_id("src/lib.rs"),
- range: Range::new(Position::new(2, 4), Position::new(2, 7)),
+ range: Range::new(Position::new(2, 8), Position::new(2, 8)),
context: CodeActionContext::default(),
partial_result_params: PartialResultParams::default(),
work_done_progress_params: WorkDoneProgressParams::default(),