Skip to content

Commit c2d3f90

Browse files
author
Côme ALLART
committed
fix: remove brackets if no generic types
1 parent 4a5341e commit c2d3f90

File tree

1 file changed

+60
-49
lines changed

1 file changed

+60
-49
lines changed

crates/ide_assists/src/handlers/generate_documentation_template.rs

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> String {
8989
let is_new = ast_func.name()?.to_string() == "new";
9090
match is_new && ret_ty == self_ty {
9191
true => {
92-
Some(format!("Creates a new [`{}`].", lifetimes_removed(&self_type(ast_func)?)))
92+
Some(format!("Creates a new [`{}`].", self_type_without_lifetimes(ast_func)?))
9393
}
9494
false => None,
9595
}
@@ -223,61 +223,32 @@ fn self_name(ast_func: &ast::Fn) -> Option<String> {
223223
}
224224

225225
/// Heper function to get the name of the type of `self`
226-
fn self_type(ast_func: &ast::Fn) -> Option<String> {
227-
ast_func
228-
.syntax()
229-
.ancestors()
230-
.find_map(ast::Impl::cast)
231-
.and_then(|i| i.self_ty())
232-
.map(|t| (t.to_string()))
226+
fn self_type(ast_func: &ast::Fn) -> Option<ast::Type> {
227+
ast_func.syntax().ancestors().find_map(ast::Impl::cast).and_then(|i| i.self_ty())
233228
}
234229

235-
/// Output the same string as the input, removing lifetimes.
236-
///
237-
/// Lifetimes are detected as starting with a `'` and ending with `,\s*` or before a `>`.
238-
fn lifetimes_removed(with_lifetimes: &str) -> String {
239-
#[derive(Debug)]
240-
enum State {
241-
OutOfLifetime,
242-
AfterLifetime,
243-
InLifetime,
244-
}
245-
246-
let mut state = State::OutOfLifetime;
247-
let mut without_lifetimes = String::new();
248-
for c in with_lifetimes.chars() {
249-
match state {
250-
State::OutOfLifetime => {
251-
if c == '\'' {
252-
state = State::InLifetime;
253-
} else {
254-
without_lifetimes.push(c);
255-
}
256-
}
257-
State::InLifetime => {
258-
if c == ',' {
259-
state = State::AfterLifetime;
260-
} else if c == '>' {
261-
without_lifetimes.push(c);
262-
state = State::OutOfLifetime;
263-
}
264-
}
265-
State::AfterLifetime => {
266-
if c == '\'' {
267-
state = State::InLifetime;
268-
} else if !c.is_whitespace() {
269-
without_lifetimes.push(c);
270-
state = State::OutOfLifetime;
271-
}
272-
}
273-
}
230+
/// Output the real name of `Self` like `MyType<T>`, without the lifetimes.
231+
fn self_type_without_lifetimes(ast_func: &ast::Fn) -> Option<String> {
232+
let path_segment =
233+
ast::PathType::cast(self_type(ast_func)?.syntax().clone())?.path()?.segment()?;
234+
let mut name = path_segment.name_ref()?.to_string();
235+
let generics = path_segment
236+
.generic_arg_list()?
237+
.generic_args()
238+
.filter(|generic| matches!(generic, ast::GenericArg::TypeArg(_)))
239+
.map(|generic| generic.to_string());
240+
let generics: String = Itertools::intersperse(generics, ", ".to_string()).collect();
241+
if !generics.is_empty() {
242+
name.push('<');
243+
name.push_str(&generics);
244+
name.push('>');
274245
}
275-
without_lifetimes
246+
Some(name)
276247
}
277248

278249
/// Heper function to get the name of the type of `self` without generic arguments
279250
fn self_partial_type(ast_func: &ast::Fn) -> Option<String> {
280-
let mut self_type = self_type(ast_func)?;
251+
let mut self_type = self_type(ast_func)?.to_string();
281252
if let Some(idx) = self_type.find(|c| ['<', ' '].contains(&c)) {
282253
self_type.truncate(idx);
283254
}
@@ -1114,6 +1085,46 @@ impl<'a, 'b, T> MyGenericStruct<'a, 'b, T> {
11141085
);
11151086
}
11161087

1088+
#[test]
1089+
fn removes_all_lifetimes_and_brackets_from_description() {
1090+
check_assist(
1091+
generate_documentation_template,
1092+
r#"
1093+
#[derive(Debug, PartialEq)]
1094+
pub struct MyGenericStruct<'a, 'b> {
1095+
pub x: &'a usize,
1096+
pub y: &'b usize,
1097+
}
1098+
impl<'a, 'b> MyGenericStruct<'a, 'b> {
1099+
pub fn new$0(x: &'a usize, y: &'b usize) -> Self {
1100+
MyGenericStruct { x, y }
1101+
}
1102+
}
1103+
"#,
1104+
r#"
1105+
#[derive(Debug, PartialEq)]
1106+
pub struct MyGenericStruct<'a, 'b> {
1107+
pub x: &'a usize,
1108+
pub y: &'b usize,
1109+
}
1110+
impl<'a, 'b> MyGenericStruct<'a, 'b> {
1111+
/// Creates a new [`MyGenericStruct`].
1112+
///
1113+
/// # Examples
1114+
///
1115+
/// ```
1116+
/// use test::MyGenericStruct;
1117+
///
1118+
/// assert_eq!(MyGenericStruct::new(x, y), );
1119+
/// ```
1120+
pub fn new(x: &'a usize, y: &'b usize) -> Self {
1121+
MyGenericStruct { x, y }
1122+
}
1123+
}
1124+
"#,
1125+
);
1126+
}
1127+
11171128
#[test]
11181129
fn detects_new_with_self() {
11191130
check_assist(

0 commit comments

Comments
 (0)