diff options
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter.rs | 113 |
1 files changed, 106 insertions, 7 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 | ||
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 | |||
132 | #[cfg(test)] | 162 | #[cfg(test)] |
133 | mod tests { | 163 | mod 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#" | ||
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 | } | ||
373 | "#, | ||
374 | ); | ||
375 | } | ||
277 | } | 376 | } |