mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
New assist: add turbo fish
This commit is contained in:
parent
1bc1f28bc5
commit
80545e5d3a
6 changed files with 176 additions and 0 deletions
134
crates/ra_assists/src/handlers/add_turbo_fish.rs
Normal file
134
crates/ra_assists/src/handlers/add_turbo_fish.rs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass};
|
||||||
|
use ra_syntax::{ast, AstNode, SyntaxKind, T};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
assist_context::{AssistContext, Assists},
|
||||||
|
AssistId,
|
||||||
|
};
|
||||||
|
use test_utils::tested_by;
|
||||||
|
|
||||||
|
// Assist: add_turbo_fish
|
||||||
|
//
|
||||||
|
// Adds `::<_>` to a call of a generic method or function.
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// fn make<T>() -> T { todo!() }
|
||||||
|
// fn main() {
|
||||||
|
// let x = make<|>();
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// ->
|
||||||
|
// ```
|
||||||
|
// fn make<T>() -> T { todo!() }
|
||||||
|
// fn main() {
|
||||||
|
// let x = make::<${0:_}>();
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
|
let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?;
|
||||||
|
let next_token = ident.next_token()?;
|
||||||
|
if next_token.kind() == T![::] {
|
||||||
|
tested_by!(add_turbo_fish_one_fish_is_enough);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let name_ref = ast::NameRef::cast(ident.parent())?;
|
||||||
|
let def = match classify_name_ref(&ctx.sema, &name_ref)? {
|
||||||
|
NameRefClass::Definition(def) => def,
|
||||||
|
NameRefClass::FieldShorthand { .. } => return None,
|
||||||
|
};
|
||||||
|
let fun = match def {
|
||||||
|
Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
|
||||||
|
if generics.is_empty() {
|
||||||
|
tested_by!(add_turbo_fish_non_generic);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| {
|
||||||
|
match ctx.config.snippet_cap {
|
||||||
|
Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
|
||||||
|
None => builder.insert(ident.text_range().end(), "::<_>"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use test_utils::covers;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_turbo_fish_function() {
|
||||||
|
check_assist(
|
||||||
|
add_turbo_fish,
|
||||||
|
r#"
|
||||||
|
fn make<T>() -> T {}
|
||||||
|
fn main() {
|
||||||
|
make<|>();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn make<T>() -> T {}
|
||||||
|
fn main() {
|
||||||
|
make::<${0:_}>();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_turbo_fish_method() {
|
||||||
|
check_assist(
|
||||||
|
add_turbo_fish,
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
fn make<T>(&self) -> T {}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
S.make<|>();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl S {
|
||||||
|
fn make<T>(&self) -> T {}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
S.make::<${0:_}>();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_turbo_fish_one_fish_is_enough() {
|
||||||
|
covers!(add_turbo_fish_one_fish_is_enough);
|
||||||
|
check_assist_not_applicable(
|
||||||
|
add_turbo_fish,
|
||||||
|
r#"
|
||||||
|
fn make<T>() -> T {}
|
||||||
|
fn main() {
|
||||||
|
make<|>::<()>();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_turbo_fish_non_generic() {
|
||||||
|
covers!(add_turbo_fish_non_generic);
|
||||||
|
check_assist_not_applicable(
|
||||||
|
add_turbo_fish,
|
||||||
|
r#"
|
||||||
|
fn make() -> () {}
|
||||||
|
fn main() {
|
||||||
|
make<|>();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -110,6 +110,7 @@ mod handlers {
|
||||||
mod add_impl;
|
mod add_impl;
|
||||||
mod add_missing_impl_members;
|
mod add_missing_impl_members;
|
||||||
mod add_new;
|
mod add_new;
|
||||||
|
mod add_turbo_fish;
|
||||||
mod apply_demorgan;
|
mod apply_demorgan;
|
||||||
mod auto_import;
|
mod auto_import;
|
||||||
mod change_return_type_to_result;
|
mod change_return_type_to_result;
|
||||||
|
@ -147,6 +148,7 @@ mod handlers {
|
||||||
add_function::add_function,
|
add_function::add_function,
|
||||||
add_impl::add_impl,
|
add_impl::add_impl,
|
||||||
add_new::add_new,
|
add_new::add_new,
|
||||||
|
add_turbo_fish::add_turbo_fish,
|
||||||
apply_demorgan::apply_demorgan,
|
apply_demorgan::apply_demorgan,
|
||||||
auto_import::auto_import,
|
auto_import::auto_import,
|
||||||
change_return_type_to_result::change_return_type_to_result,
|
change_return_type_to_result::change_return_type_to_result,
|
||||||
|
|
|
@ -9,4 +9,6 @@ test_utils::marks![
|
||||||
test_not_applicable_if_variable_unused
|
test_not_applicable_if_variable_unused
|
||||||
change_visibility_field_false_positive
|
change_visibility_field_false_positive
|
||||||
test_add_from_impl_already_exists
|
test_add_from_impl_already_exists
|
||||||
|
add_turbo_fish_one_fish_is_enough
|
||||||
|
add_turbo_fish_non_generic
|
||||||
];
|
];
|
||||||
|
|
|
@ -211,6 +211,25 @@ impl<T: Clone> Ctx<T> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doctest_add_turbo_fish() {
|
||||||
|
check_doc_test(
|
||||||
|
"add_turbo_fish",
|
||||||
|
r#####"
|
||||||
|
fn make<T>() -> T { todo!() }
|
||||||
|
fn main() {
|
||||||
|
let x = make<|>();
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
r#####"
|
||||||
|
fn make<T>() -> T { todo!() }
|
||||||
|
fn main() {
|
||||||
|
let x = make::<${0:_}>();
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doctest_apply_demorgan() {
|
fn doctest_apply_demorgan() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
|
|
|
@ -203,6 +203,24 @@ impl<T: Clone> Ctx<T> {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `add_turbo_fish`
|
||||||
|
|
||||||
|
Adds `::<_>` to a call of a generic method or function.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// BEFORE
|
||||||
|
fn make<T>() -> T { todo!() }
|
||||||
|
fn main() {
|
||||||
|
let x = make┃();
|
||||||
|
}
|
||||||
|
|
||||||
|
// AFTER
|
||||||
|
fn make<T>() -> T { todo!() }
|
||||||
|
fn main() {
|
||||||
|
let x = make::<${0:_}>();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## `apply_demorgan`
|
## `apply_demorgan`
|
||||||
|
|
||||||
Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
|
Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
|
||||||
|
|
|
@ -57,6 +57,7 @@ fn check_todo(path: &Path, text: &str) {
|
||||||
"tests/generated.rs",
|
"tests/generated.rs",
|
||||||
"handlers/add_missing_impl_members.rs",
|
"handlers/add_missing_impl_members.rs",
|
||||||
"handlers/add_function.rs",
|
"handlers/add_function.rs",
|
||||||
|
"handlers/add_turbo_fish.rs",
|
||||||
// To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
|
// To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
|
||||||
"ast/make.rs",
|
"ast/make.rs",
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue