+use ast::Adt;
use itertools::Itertools;
use stdx::format_to;
-use syntax::{
- ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner},
- SmolStr,
-};
+use syntax::ast::{self, AstNode, NameOwner, StructKind, VisibilityOwner};
use crate::{
- utils::{find_impl_block, find_struct_impl},
+ utils::{find_impl_block, find_struct_impl, generate_impl_text},
AssistContext, AssistId, AssistKind, Assists,
};
// impl<T: Clone> Ctx<T> {
// fn $0new(data: T) -> Self { Self { data } }
// }
-//
// ```
pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
};
// Return early if we've found an existing new fn
- let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), "new")?;
+ let impl_def = find_struct_impl(&ctx, &Adt::Struct(strukt.clone()), "new")?;
let target = strukt.syntax().text_range();
acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
let start_offset = impl_def
.and_then(|impl_def| find_impl_block(impl_def, &mut buf))
.unwrap_or_else(|| {
- buf = generate_impl_text(&strukt, &buf);
+ buf = generate_impl_text(&Adt::Struct(strukt.clone()), &buf);
strukt.syntax().text_range().end()
});
})
}
-// Generates the surrounding `impl Type { <code> }` including type and lifetime
-// parameters
-fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String {
- let type_params = strukt.generic_param_list();
- let mut buf = String::with_capacity(code.len());
- buf.push_str("\n\nimpl");
- if let Some(type_params) = &type_params {
- format_to!(buf, "{}", type_params.syntax());
- }
- buf.push(' ');
- buf.push_str(strukt.name().unwrap().text());
- if let Some(type_params) = type_params {
- let lifetime_params = type_params
- .lifetime_params()
- .filter_map(|it| it.lifetime())
- .map(|it| SmolStr::from(it.text()));
- let type_params =
- type_params.type_params().filter_map(|it| it.name()).map(|it| SmolStr::from(it.text()));
- format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", "))
- }
-
- format_to!(buf, " {{\n{}\n}}\n", code);
-
- buf
-}
-
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
impl Foo {
fn $0new() -> Self { Self { } }
-}
-",
+}",
);
check_assist(
generate_new,
impl<T: Clone> Foo<T> {
fn $0new() -> Self { Self { } }
-}
-",
+}",
);
check_assist(
generate_new,
impl<'a, T: Foo<'a>> Foo<'a, T> {
fn $0new() -> Self { Self { } }
-}
-",
+}",
);
check_assist(
generate_new,
impl Foo {
fn $0new(baz: String) -> Self { Self { baz } }
-}
-",
+}",
);
check_assist(
generate_new,
impl Foo {
fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
-}
-",
+}",
);
// Check that visibility modifiers don't get brought in for fields
impl Foo {
fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
-}
-",
+}",
);
// Check that it reuses existing impls
impl Foo {
pub fn $0new() -> Self { Self { } }
-}
-",
+}",
);
check_assist(
generate_new,
impl Foo {
pub(crate) fn $0new() -> Self { Self { } }
-}
-",
+}",
);
}
pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
Source { file_id: self.file_id, ast: f(self.ast) }
}
-}
-"##,
+}"##,
r##"
pub struct AstId<N: AstNode> {
file_id: HirFileId,
pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
Source { file_id: self.file_id, ast: f(self.ast) }
}
-}
-"##,
+}"##,
);
}
}