feat: generate getter avoids generating types like &Vec<T>

This commit is contained in:
Aleksey Kladov 2021-05-24 00:05:14 +03:00
parent 951c0e95f4
commit 479a7387c2
2 changed files with 108 additions and 9 deletions

View File

@ -23,8 +23,8 @@ use crate::{
// //
// impl Person { // impl Person {
// /// Get a reference to the person's name. // /// Get a reference to the person's name.
// fn $0name(&self) -> &String { // fn $0name(&self) -> &str {
// &self.name // 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 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!( format_to!(
buf, buf,
" /// Get a {}reference to the {}'s {}. " /// Get a {}reference to the {}'s {}.
{}fn {}(&{mut_}self) -> &{mut_}{} {{ {}fn {}(&{}self) -> {} {{
&{mut_}self.{} {}
}}", }}",
mutable.then(|| "mutable ").unwrap_or_default(), mutable.then(|| "mutable ").unwrap_or_default(),
to_lower_snake_case(&strukt_name.to_string()).replace('_', " "), to_lower_snake_case(&strukt_name.to_string()).replace('_', " "),
fn_name.trim_end_matches("_mut").replace('_', " "), fn_name.trim_end_matches("_mut").replace('_', " "),
vis, vis,
fn_name, fn_name,
field_ty, mutable.then(|| "mut ").unwrap_or_default(),
field_name, ty,
mut_ = mutable.then(|| "mut ").unwrap_or_default(), body,
); );
let start_offset = impl_def 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<String> {
let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string();
Some(res)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests::{check_assist, check_assist_not_applicable}; use crate::tests::{check_assist, check_assist_not_applicable};
@ -271,6 +301,75 @@ impl Context {
&self.count &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<Sweets> }
"#,
r#"
struct S { foo: Box<Sweets> }
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<Failure> }
"#,
r#"
struct S { foo: Option<Failure> }
impl S {
/// Get a reference to the s's foo.
fn $0foo(&self) -> Option<&Failure> {
self.foo.as_ref()
}
}
"#, "#,
); );
} }

View File

@ -786,8 +786,8 @@ struct Person {
impl Person { impl Person {
/// Get a reference to the person's name. /// Get a reference to the person's name.
fn $0name(&self) -> &String { fn $0name(&self) -> &str {
&self.name self.name.as_str()
} }
} }
"#####, "#####,