diff options
| author | Lukas Wirth <lukastw97@gmail.com> | 2025-05-05 09:37:14 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-05 09:37:14 +0000 |
| commit | a6e71bafcbe73e84abed8a037d4f350456a878ed (patch) | |
| tree | 96701f181e0523b5a64c3dbbcad8bcfd1f9ba1e8 | |
| parent | d24c37ed03504a8f872681b97bdce1d0a1d721b9 (diff) | |
| parent | 77f7a9afb84ad729973e78f9fb692c10c6deefda (diff) | |
| download | rust-a6e71bafcbe73e84abed8a037d4f350456a878ed.tar.gz rust-a6e71bafcbe73e84abed8a037d4f350456a878ed.zip | |
Merge pull request #19740 from vishruth-thimmaiah/unwrap_path_type
feat: add an assist to unwrap a type with a generic arg
3 files changed, 175 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs new file mode 100644 index 00000000000..7b5adc1858b --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_type_to_generic_arg.rs @@ -0,0 +1,156 @@ +use ide_db::assists::AssistId; +use syntax::{ + AstNode, + ast::{self, GenericArg, HasGenericArgs}, +}; + +use crate::{AssistContext, Assists}; + +// Assist: unwrap_type_to_generic_arg +// +// This assist unwraps a type into its generic type argument. +// +// ``` +// fn foo() -> $0Option<i32> { +// todo!() +// } +// ``` +// -> +// ``` +// fn foo() -> i32 { +// todo!() +// } +// ``` +pub(crate) fn unwrap_type_to_generic_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let path_type = ctx.find_node_at_offset::<ast::PathType>()?; + let path = path_type.path()?; + let segment = path.segment()?; + let args_list = segment.generic_arg_list()?; + + let mut generic_arg = None; + + for arg in args_list.generic_args() { + match arg { + GenericArg::ConstArg(_) | GenericArg::LifetimeArg(_) => (), + GenericArg::TypeArg(arg) if generic_arg.is_none() => { + generic_arg = Some(arg); + } + _ => return None, + } + } + + let generic_arg = generic_arg?; + + acc.add( + AssistId::refactor_extract("unwrap_type_to_generic_arg"), + format!("Unwrap type to type argument {generic_arg}"), + path_type.syntax().text_range(), + |builder| { + let mut editor = builder.make_editor(path_type.syntax()); + editor.replace(path_type.syntax(), generic_arg.syntax()); + + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::{check_assist, check_assist_not_applicable}; + + #[test] + fn test_unwrap_type_to_generic_arg() { + check_assist( + unwrap_type_to_generic_arg, + r#" +//- minicore: option +fn foo() -> $0Option<i32> { + todo!() +} +"#, + r#" +fn foo() -> i32 { + todo!() +} +"#, + ); + } + + #[test] + fn unwrap_type_to_generic_arg_not_applicable_for_non_generic_arg_list() { + check_assist_not_applicable( + unwrap_type_to_generic_arg, + r#" +fn foo() -> $0i32 {} +"#, + ); + } + + #[test] + fn unwrap_type_to_generic_arg_not_applicable_for_multiple_generic_args() { + check_assist_not_applicable( + unwrap_type_to_generic_arg, + r#" +//- minicore: result +fn foo() -> $0Result<i32, ()> { + todo!() +} +"#, + ); + } + + #[test] + fn unwrap_type_to_generic_arg_with_lifetime_and_const() { + check_assist( + unwrap_type_to_generic_arg, + r#" +enum Foo<'a, T, const N: usize> { + Bar(T), + Baz(&'a [T; N]), +} + +fn test<'a>() -> $0Foo<'a, i32, 3> { + todo!() +} +"#, + r#" +enum Foo<'a, T, const N: usize> { + Bar(T), + Baz(&'a [T; N]), +} + +fn test<'a>() -> i32 { + todo!() +} +"#, + ); + } + + #[test] + fn unwrap_type_to_generic_arg_in_let_stmt() { + check_assist( + unwrap_type_to_generic_arg, + r#" +enum Foo<T> { + Bar(T), + Baz, +} + +fn test() { + let foo: $0Foo<i32> = todo!(); +} +"#, + r#" +enum Foo<T> { + Bar(T), + Baz, +} + +fn test() { + let foo: i32 = todo!(); +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 627ed37b04e..2395091b6f2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -229,6 +229,7 @@ mod handlers { mod unwrap_block; mod unwrap_return_type; mod unwrap_tuple; + mod unwrap_type_to_generic_arg; mod wrap_return_type; mod wrap_unwrap_cfg_attr; @@ -369,6 +370,7 @@ mod handlers { unwrap_block::unwrap_block, unwrap_return_type::unwrap_return_type, unwrap_tuple::unwrap_tuple, + unwrap_type_to_generic_arg::unwrap_type_to_generic_arg, wrap_return_type::wrap_return_type, wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 01ab0be34b2..76134acb36e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -3482,6 +3482,23 @@ fn main() { } #[test] +fn doctest_unwrap_type_to_generic_arg() { + check_doc_test( + "unwrap_type_to_generic_arg", + r#####" +fn foo() -> $0Option<i32> { + todo!() +} +"#####, + r#####" +fn foo() -> i32 { + todo!() +} +"#####, + ) +} + +#[test] fn doctest_wrap_return_type_in_option() { check_doc_test( "wrap_return_type_in_option", |
