Skip to content

Commit a2ce091

Browse files
bors[bot]matklad
andauthored
Merge #8953
8953: feat: generate getter avoids generating types like `&Vec<T>` r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 4e376ba + 479a738 commit a2ce091

File tree

2 files changed

+108
-9
lines changed

2 files changed

+108
-9
lines changed

crates/ide_assists/src/handlers/generate_getter.rs

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use crate::{
2323
//
2424
// impl Person {
2525
// /// Get a reference to the person's name.
26-
// fn $0name(&self) -> &String {
27-
// &self.name
26+
// fn $0name(&self) -> &str {
27+
// self.name.as_str()
2828
// }
2929
// }
3030
// ```
@@ -96,20 +96,27 @@ pub(crate) fn generate_getter_impl(
9696
}
9797

9898
let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
99+
let (ty, body) = if mutable {
100+
(format!("&mut {}", field_ty), format!("&mut self.{}", field_name))
101+
} else {
102+
useless_type_special_case(&field_name.to_string(), &field_ty)
103+
.unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name)))
104+
};
105+
99106
format_to!(
100107
buf,
101108
" /// Get a {}reference to the {}'s {}.
102-
{}fn {}(&{mut_}self) -> &{mut_}{} {{
103-
&{mut_}self.{}
109+
{}fn {}(&{}self) -> {} {{
110+
{}
104111
}}",
105112
mutable.then(|| "mutable ").unwrap_or_default(),
106113
to_lower_snake_case(&strukt_name.to_string()).replace('_', " "),
107114
fn_name.trim_end_matches("_mut").replace('_', " "),
108115
vis,
109116
fn_name,
110-
field_ty,
111-
field_name,
112-
mut_ = mutable.then(|| "mut ").unwrap_or_default(),
117+
mutable.then(|| "mut ").unwrap_or_default(),
118+
ty,
119+
body,
113120
);
114121

115122
let start_offset = impl_def
@@ -129,6 +136,29 @@ pub(crate) fn generate_getter_impl(
129136
)
130137
}
131138

139+
fn useless_type_special_case(field_name: &str, field_ty: &ast::Type) -> Option<(String, String)> {
140+
if field_ty.to_string() == "String" {
141+
cov_mark::hit!(useless_type_special_case);
142+
return Some(("&str".to_string(), format!("self.{}.as_str()", field_name)));
143+
}
144+
if let Some(arg) = ty_ctor(field_ty, "Vec") {
145+
return Some((format!("&[{}]", arg), format!("self.{}.as_slice()", field_name)));
146+
}
147+
if let Some(arg) = ty_ctor(field_ty, "Box") {
148+
return Some((format!("&{}", arg), format!("self.{}.as_ref()", field_name)));
149+
}
150+
if let Some(arg) = ty_ctor(field_ty, "Option") {
151+
return Some((format!("Option<&{}>", arg), format!("self.{}.as_ref()", field_name)));
152+
}
153+
None
154+
}
155+
156+
// FIXME: This should rely on semantic info.
157+
fn ty_ctor(ty: &ast::Type, ctor: &str) -> Option<String> {
158+
let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string();
159+
Some(res)
160+
}
161+
132162
#[cfg(test)]
133163
mod tests {
134164
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -271,6 +301,75 @@ impl Context {
271301
&self.count
272302
}
273303
}
304+
"#,
305+
);
306+
}
307+
308+
#[test]
309+
fn test_special_cases() {
310+
cov_mark::check!(useless_type_special_case);
311+
check_assist(
312+
generate_getter,
313+
r#"
314+
struct S { foo: $0String }
315+
"#,
316+
r#"
317+
struct S { foo: String }
318+
319+
impl S {
320+
/// Get a reference to the s's foo.
321+
fn $0foo(&self) -> &str {
322+
self.foo.as_str()
323+
}
324+
}
325+
"#,
326+
);
327+
check_assist(
328+
generate_getter,
329+
r#"
330+
struct S { foo: $0Box<Sweets> }
331+
"#,
332+
r#"
333+
struct S { foo: Box<Sweets> }
334+
335+
impl S {
336+
/// Get a reference to the s's foo.
337+
fn $0foo(&self) -> &Sweets {
338+
self.foo.as_ref()
339+
}
340+
}
341+
"#,
342+
);
343+
check_assist(
344+
generate_getter,
345+
r#"
346+
struct S { foo: $0Vec<()> }
347+
"#,
348+
r#"
349+
struct S { foo: Vec<()> }
350+
351+
impl S {
352+
/// Get a reference to the s's foo.
353+
fn $0foo(&self) -> &[()] {
354+
self.foo.as_slice()
355+
}
356+
}
357+
"#,
358+
);
359+
check_assist(
360+
generate_getter,
361+
r#"
362+
struct S { foo: $0Option<Failure> }
363+
"#,
364+
r#"
365+
struct S { foo: Option<Failure> }
366+
367+
impl S {
368+
/// Get a reference to the s's foo.
369+
fn $0foo(&self) -> Option<&Failure> {
370+
self.foo.as_ref()
371+
}
372+
}
274373
"#,
275374
);
276375
}

crates/ide_assists/src/tests/generated.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,8 +786,8 @@ struct Person {
786786
787787
impl Person {
788788
/// Get a reference to the person's name.
789-
fn $0name(&self) -> &String {
790-
&self.name
789+
fn $0name(&self) -> &str {
790+
self.name.as_str()
791791
}
792792
}
793793
"#####,

0 commit comments

Comments
 (0)