aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-05-23 22:05:14 +0100
committerAleksey Kladov <[email protected]>2021-05-23 22:15:23 +0100
commit479a7387c26de025d00dd926afc3cf311484574d (patch)
treecace14f992a94107249302a3659d45fa0340d8a3 /crates
parent951c0e95f44bf7947c2a46ef9e8ff2616823faba (diff)
feat: generate getter avoids generating types like `&Vec<T>`
Diffstat (limited to 'crates')
-rw-r--r--crates/ide_assists/src/handlers/generate_getter.rs113
-rw-r--r--crates/ide_assists/src/tests/generated.rs4
2 files changed, 108 insertions, 9 deletions
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index 9faaaf284..09971226e 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -23,8 +23,8 @@ use crate::{
23// 23//
24// impl Person { 24// impl Person {
25// /// Get a reference to the person's name. 25// /// Get a reference to the person's name.
26// fn $0name(&self) -> &String { 26// fn $0name(&self) -> &str {
27// &self.name 27// self.name.as_str()
28// } 28// }
29// } 29// }
30// ``` 30// ```
@@ -96,20 +96,27 @@ pub(crate) fn generate_getter_impl(
96 } 96 }
97 97
98 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); 98 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
99 format_to!( 106 format_to!(
100 buf, 107 buf,
101 " /// Get a {}reference to the {}'s {}. 108 " /// Get a {}reference to the {}'s {}.
102 {}fn {}(&{mut_}self) -> &{mut_}{} {{ 109 {}fn {}(&{}self) -> {} {{
103 &{mut_}self.{} 110 {}
104 }}", 111 }}",
105 mutable.then(|| "mutable ").unwrap_or_default(), 112 mutable.then(|| "mutable ").unwrap_or_default(),
106 to_lower_snake_case(&strukt_name.to_string()).replace('_', " "), 113 to_lower_snake_case(&strukt_name.to_string()).replace('_', " "),
107 fn_name.trim_end_matches("_mut").replace('_', " "), 114 fn_name.trim_end_matches("_mut").replace('_', " "),
108 vis, 115 vis,
109 fn_name, 116 fn_name,
110 field_ty, 117 mutable.then(|| "mut ").unwrap_or_default(),
111 field_name, 118 ty,
112 mut_ = mutable.then(|| "mut ").unwrap_or_default(), 119 body,
113 ); 120 );
114 121
115 let start_offset = impl_def 122 let start_offset = impl_def
@@ -129,6 +136,29 @@ pub(crate) fn generate_getter_impl(
129 ) 136 )
130} 137}
131 138
139fn 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.
157fn 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
132#[cfg(test)] 162#[cfg(test)]
133mod tests { 163mod tests {
134 use crate::tests::{check_assist, check_assist_not_applicable}; 164 use crate::tests::{check_assist, check_assist_not_applicable};
@@ -274,4 +304,73 @@ impl Context {
274"#, 304"#,
275 ); 305 );
276 } 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#"
314struct S { foo: $0String }
315"#,
316 r#"
317struct S { foo: String }
318
319impl 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#"
330struct S { foo: $0Box<Sweets> }
331"#,
332 r#"
333struct S { foo: Box<Sweets> }
334
335impl 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#"
346struct S { foo: $0Vec<()> }
347"#,
348 r#"
349struct S { foo: Vec<()> }
350
351impl 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#"
362struct S { foo: $0Option<Failure> }
363"#,
364 r#"
365struct S { foo: Option<Failure> }
366
367impl S {
368 /// Get a reference to the s's foo.
369 fn $0foo(&self) -> Option<&Failure> {
370 self.foo.as_ref()
371 }
372}
373"#,
374 );
375 }
277} 376}
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index ffc915fd4..8a9b0777c 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -786,8 +786,8 @@ struct Person {
786 786
787impl Person { 787impl Person {
788 /// Get a reference to the person's name. 788 /// Get a reference to the person's name.
789 fn $0name(&self) -> &String { 789 fn $0name(&self) -> &str {
790 &self.name 790 self.name.as_str()
791 } 791 }
792} 792}
793"#####, 793"#####,