mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +00:00
add static method generation assist
This commit is contained in:
parent
996300f4a0
commit
cf5f1c102c
1 changed files with 148 additions and 19 deletions
|
@ -70,26 +70,56 @@ impl FuncExpr {
|
|||
fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
|
||||
let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
|
||||
|
||||
let path = path_expr.path()?;
|
||||
let fn_name = fn_name(&path)?;
|
||||
if ctx.sema.resolve_path(&path).is_some() {
|
||||
// The function call already resolves, no need to add a function
|
||||
return None;
|
||||
}
|
||||
|
||||
let target_module = match path.qualifier() {
|
||||
Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
|
||||
Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => Some(module),
|
||||
_ => return None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
let target_module;
|
||||
let mut adt_name = None;
|
||||
|
||||
let (target, file, insert_offset) = get_fn_target(ctx, &target_module, call.clone())?;
|
||||
let (target, file, insert_offset) = match path.qualifier() {
|
||||
Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
|
||||
Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => {
|
||||
target_module = Some(module);
|
||||
get_fn_target(ctx, &target_module, call.clone())?
|
||||
}
|
||||
Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
|
||||
let current_module = current_module(call.syntax(), ctx)?;
|
||||
let module = adt.module(ctx.sema.db);
|
||||
target_module = if current_module == module { None } else { Some(module) };
|
||||
if current_module.krate() != module.krate() {
|
||||
return None;
|
||||
}
|
||||
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
|
||||
let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
|
||||
adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
|
||||
(target, file, insert_offset)
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
target_module = None;
|
||||
get_fn_target(ctx, &target_module, call.clone())?
|
||||
}
|
||||
};
|
||||
let function_builder = FunctionBuilder::from_call(ctx, &call, &path, target_module, target)?;
|
||||
let target = call.syntax().text_range();
|
||||
let text_range = call.syntax().text_range();
|
||||
let label = format!("Generate {} function", function_builder.fn_name.clone());
|
||||
add_func_to_accumulator(acc, ctx, target, function_builder, insert_offset, file, None, label)
|
||||
add_func_to_accumulator(
|
||||
acc,
|
||||
ctx,
|
||||
text_range,
|
||||
function_builder,
|
||||
insert_offset,
|
||||
file,
|
||||
adt_name,
|
||||
label,
|
||||
)
|
||||
}
|
||||
|
||||
fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
|
@ -103,13 +133,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
|||
if current_module.krate() != target_module.krate() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
|
||||
let file = ctx.sema.parse(range.file_id);
|
||||
let adt_source =
|
||||
ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
|
||||
let impl_ = find_struct_impl(ctx, &adt_source, fn_name.text().as_str())?;
|
||||
|
||||
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
|
||||
let (target, insert_offset) = get_method_target(ctx, &target_module, &impl_)?;
|
||||
let function_builder =
|
||||
FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
|
||||
|
@ -122,7 +146,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
|||
text_range,
|
||||
function_builder,
|
||||
insert_offset,
|
||||
range.file_id,
|
||||
file,
|
||||
adt_name,
|
||||
label,
|
||||
)
|
||||
|
@ -156,6 +180,18 @@ fn current_module(current_node: &SyntaxNode, ctx: &AssistContext) -> Option<Modu
|
|||
ctx.sema.scope(current_node).module()
|
||||
}
|
||||
|
||||
fn get_adt_source(
|
||||
ctx: &AssistContext,
|
||||
adt: &hir::Adt,
|
||||
fn_name: &str,
|
||||
) -> Option<(Option<ast::Impl>, FileId)> {
|
||||
let range = adt.source(ctx.sema.db)?.syntax().original_file_range(ctx.sema.db);
|
||||
let file = ctx.sema.parse(range.file_id);
|
||||
let adt_source =
|
||||
ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
|
||||
find_struct_impl(ctx, &adt_source, fn_name).map(|impl_| (impl_, range.file_id))
|
||||
}
|
||||
|
||||
struct FunctionTemplate {
|
||||
leading_ws: String,
|
||||
fn_def: ast::Fn,
|
||||
|
@ -1514,6 +1550,99 @@ fn bar(&self) ${0:-> ()} {
|
|||
todo!()
|
||||
}
|
||||
}
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_static_method() {
|
||||
check_assist(
|
||||
generate_function,
|
||||
r"
|
||||
struct S;
|
||||
fn foo() {S::bar$0();}
|
||||
",
|
||||
r"
|
||||
struct S;
|
||||
fn foo() {S::bar();}
|
||||
impl S {
|
||||
|
||||
|
||||
fn bar() ${0:-> ()} {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_static_method_within_an_impl() {
|
||||
check_assist(
|
||||
generate_function,
|
||||
r"
|
||||
struct S;
|
||||
fn foo() {S::bar$0();}
|
||||
impl S {}
|
||||
|
||||
",
|
||||
r"
|
||||
struct S;
|
||||
fn foo() {S::bar();}
|
||||
impl S {
|
||||
fn bar() ${0:-> ()} {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_static_method_from_different_module() {
|
||||
check_assist(
|
||||
generate_function,
|
||||
r"
|
||||
mod s {
|
||||
pub struct S;
|
||||
}
|
||||
fn foo() {s::S::bar$0();}
|
||||
",
|
||||
r"
|
||||
mod s {
|
||||
pub struct S;
|
||||
impl S {
|
||||
|
||||
|
||||
pub(crate) fn bar() ${0:-> ()} {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
fn foo() {s::S::bar();}
|
||||
",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_static_method_with_cursor_anywhere_on_call_expresion() {
|
||||
check_assist(
|
||||
generate_function,
|
||||
r"
|
||||
struct S;
|
||||
fn foo() {$0S::bar();}
|
||||
",
|
||||
r"
|
||||
struct S;
|
||||
fn foo() {S::bar();}
|
||||
impl S {
|
||||
|
||||
|
||||
fn bar() ${0:-> ()} {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
",
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue