From 93b62dbe852837e37f8fe43c76a1105d2b221e6a Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 18 May 2022 18:05:21 +0200 Subject: [PATCH] Improve docs generation assist --- .../generate_documentation_template.rs | 569 +++++++----------- crates/ide-assists/src/lib.rs | 1 + crates/ide-assists/src/tests/generated.rs | 53 +- crates/rust-analyzer/tests/slow-tests/main.rs | 4 +- 4 files changed, 252 insertions(+), 375 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_documentation_template.rs b/crates/ide-assists/src/handlers/generate_documentation_template.rs index 7864ca2a4e5..74c71f13ee3 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::()?; 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 { + 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(¶m_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, ¶m_list, self_name.as_deref(), is_unsafe)?; + if returns_a_value(ast_func, ctx) { + if count_parameters(¶m_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 { 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 Option Option Option> { - 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> { match can_panic(ast_func) { @@ -176,44 +267,6 @@ fn safety_builder(ast_func: &ast::Fn) -> Option> { } } -/// Generates an example template -fn gen_ex_template(ast_func: &ast::Fn, ctx: &AssistContext) -> Option> { - 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(¶m_list); - let self_name: Option = 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, ¶m_list, self_name.as_deref(), is_unsafe)?; - if returns_a_value(ast_func, ctx) { - if count_parameters(¶m_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 { let hir_func = ctx.sema.to_def(ast_func)?; @@ -319,15 +372,6 @@ fn is_ref_mut_self(ast_func: &ast::Fn) -> Option { 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 { - 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() { @@ -475,54 +519,6 @@ 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() { - check_assist_not_applicable( - generate_documentation_template, - r#" -mod PrivateModule { - pub fn pri$0vate() {} -}"#, - ); - } - - #[test] - fn not_applicable_if_function_is_in_pub_crate_mod() { - check_assist_not_applicable( - generate_documentation_template, - r#" -pub(crate) mod PrivateModule { - pub fn pr$0ivate() {} -}"#, - ); - } - - #[test] - fn not_applicable_if_function_is_in_non_public_mod_is_recursive() { - check_assist_not_applicable( - generate_documentation_template, - r#" -mod ParentPrivateModule { - pub mod PrivateModule { - pub fn pr$0ivate() {} - } -}"#, - ); - } - #[test] fn not_applicable_if_function_already_documented() { check_assist_not_applicable( @@ -543,25 +539,43 @@ pub fn no$0op() {} "#, r#" /// . -/// -/// # Examples -/// -/// ``` -/// use test::noop; -/// -/// noop(); -/// ``` pub fn noop() {} "#, ); } + #[test] + fn is_applicable_if_function_is_private() { + check_assist( + generate_documentation_template, + r#" +fn priv$0ate() {} +"#, + r#" +/// . +fn private() {} +"#, + ); + } + + #[test] + fn no_doc_example_for_private_fn() { + check_assist_not_applicable( + generate_doc_example, + r#" +///$0 +fn private() {} +"#, + ); + } + #[test] fn supports_a_parameter() { check_assist( - generate_documentation_template, + generate_doc_example, r#" -pub fn no$0op_with_param(_a: i32) {} +/// $0. +pub fn noop_with_param(_a: i32) {} "#, r#" /// . @@ -588,6 +602,29 @@ pub unsafe fn no$0op_unsafe() {} r#" /// . /// +/// # Safety +/// +/// . +pub unsafe fn noop_unsafe() {} +"#, + ); + check_assist( + generate_doc_example, + r#" +/// . +/// +/// # 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 { 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 { #[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 /// @@ -897,30 +895,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( @@ -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 { } impl MyGenericStruct { /// Creates a new [`MyGenericStruct`]. - /// - /// # Examples - /// - /// ``` - /// use test::MyGenericStruct; - /// - /// assert_eq!(MyGenericStruct::new(x), ); - /// ``` pub fn new(x: T) -> MyGenericStruct { MyGenericStruct { x } } @@ -1069,14 +1017,6 @@ pub struct MyGenericStruct<'a, T> { } impl<'a, T> MyGenericStruct<'a, T> { /// Creates a new [`MyGenericStruct`]. - /// - /// # 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`]. - /// - /// # 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 { } impl MyGenericStruct2 { /// Creates a new [`MyGenericStruct2`]. - /// - /// # Examples - /// - /// ``` - /// use test::MyGenericStruct2; - /// - /// assert_eq!(MyGenericStruct2::new(x), ); - /// ``` pub fn new(x: T) -> Self { MyGenericStruct2 { x } } @@ -1206,15 +1122,16 @@ impl MyGenericStruct2 { #[test] fn supports_method_call() { check_assist( - generate_documentation_template, + generate_doc_example, r#" impl MyGenericStruct { - pub fn co$0nsume(self) {} + ///$0 + pub fn consume(self) {} } "#, r#" impl MyGenericStruct { - /// . + /// /// /// # Examples /// @@ -1233,17 +1150,18 @@ impl MyGenericStruct { #[test] fn checks_modified_self_param() { check_assist( - generate_documentation_template, + generate_doc_example, r#" impl MyGenericStruct { - pub fn modi$0fy(&mut self, new_value: T) { + ///$0 + pub fn modify(&mut self, new_value: T) { self.x = new_value; } } "#, r#" impl MyGenericStruct { - /// . + /// /// /// # 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) {} } "#, @@ -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 a5dfb5d2953..f78dbf2ab83 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 7772563b838..0da4197afe8 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 143b63e11c5..5bb925f62be 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::( 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::( 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(),