From 479a7387c26de025d00dd926afc3cf311484574d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 24 May 2021 00:05:14 +0300 Subject: feat: generate getter avoids generating types like `&Vec` --- crates/ide_assists/src/handlers/generate_getter.rs | 113 +++++++++++++++++++-- crates/ide_assists/src/tests/generated.rs | 4 +- 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::{ // // impl Person { // /// Get a reference to the person's name. -// fn $0name(&self) -> &String { -// &self.name +// fn $0name(&self) -> &str { +// self.name.as_str() // } // } // ``` @@ -96,20 +96,27 @@ pub(crate) fn generate_getter_impl( } let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); + let (ty, body) = if mutable { + (format!("&mut {}", field_ty), format!("&mut self.{}", field_name)) + } else { + useless_type_special_case(&field_name.to_string(), &field_ty) + .unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name))) + }; + format_to!( buf, " /// Get a {}reference to the {}'s {}. - {}fn {}(&{mut_}self) -> &{mut_}{} {{ - &{mut_}self.{} + {}fn {}(&{}self) -> {} {{ + {} }}", mutable.then(|| "mutable ").unwrap_or_default(), to_lower_snake_case(&strukt_name.to_string()).replace('_', " "), fn_name.trim_end_matches("_mut").replace('_', " "), vis, fn_name, - field_ty, - field_name, - mut_ = mutable.then(|| "mut ").unwrap_or_default(), + mutable.then(|| "mut ").unwrap_or_default(), + ty, + body, ); let start_offset = impl_def @@ -129,6 +136,29 @@ pub(crate) fn generate_getter_impl( ) } +fn useless_type_special_case(field_name: &str, field_ty: &ast::Type) -> Option<(String, String)> { + if field_ty.to_string() == "String" { + cov_mark::hit!(useless_type_special_case); + return Some(("&str".to_string(), format!("self.{}.as_str()", field_name))); + } + if let Some(arg) = ty_ctor(field_ty, "Vec") { + return Some((format!("&[{}]", arg), format!("self.{}.as_slice()", field_name))); + } + if let Some(arg) = ty_ctor(field_ty, "Box") { + return Some((format!("&{}", arg), format!("self.{}.as_ref()", field_name))); + } + if let Some(arg) = ty_ctor(field_ty, "Option") { + return Some((format!("Option<&{}>", arg), format!("self.{}.as_ref()", field_name))); + } + None +} + +// FIXME: This should rely on semantic info. +fn ty_ctor(ty: &ast::Type, ctor: &str) -> Option { + let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string(); + Some(res) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -271,6 +301,75 @@ impl Context { &self.count } } +"#, + ); + } + + #[test] + fn test_special_cases() { + cov_mark::check!(useless_type_special_case); + check_assist( + generate_getter, + r#" +struct S { foo: $0String } +"#, + r#" +struct S { foo: String } + +impl S { + /// Get a reference to the s's foo. + fn $0foo(&self) -> &str { + self.foo.as_str() + } +} +"#, + ); + check_assist( + generate_getter, + r#" +struct S { foo: $0Box } +"#, + r#" +struct S { foo: Box } + +impl S { + /// Get a reference to the s's foo. + fn $0foo(&self) -> &Sweets { + self.foo.as_ref() + } +} +"#, + ); + check_assist( + generate_getter, + r#" +struct S { foo: $0Vec<()> } +"#, + r#" +struct S { foo: Vec<()> } + +impl S { + /// Get a reference to the s's foo. + fn $0foo(&self) -> &[()] { + self.foo.as_slice() + } +} +"#, + ); + check_assist( + generate_getter, + r#" +struct S { foo: $0Option } +"#, + r#" +struct S { foo: Option } + +impl S { + /// Get a reference to the s's foo. + fn $0foo(&self) -> Option<&Failure> { + self.foo.as_ref() + } +} "#, ); } 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 { impl Person { /// Get a reference to the person's name. - fn $0name(&self) -> &String { - &self.name + fn $0name(&self) -> &str { + self.name.as_str() } } "#####, -- cgit v1.2.3