From 90b181c8e137d10991733064fd5cefef98658ffa Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sun, 13 Oct 2024 10:53:38 -0400 Subject: [PATCH 01/32] Add wrap/unwrap return type in Option --- .../src/handlers/unwrap_option_return_type.rs | 1143 ++++++++++++++++ .../handlers/wrap_return_type_in_option.rs | 1173 +++++++++++++++++ .../crates/ide-assists/src/lib.rs | 4 + .../crates/ide-assists/src/tests/generated.rs | 28 + 4 files changed, 2348 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs new file mode 100644 index 0000000000000..8dc40842406ba --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs @@ -0,0 +1,1143 @@ +use ide_db::{ + famous_defs::FamousDefs, + syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, +}; +use itertools::Itertools; +use syntax::{ + ast::{self, Expr, HasGenericArgs}, + match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: unwrap_option_return_type +// +// Unwrap the function's return type. +// +// ``` +// # //- minicore: option +// fn foo() -> Option$0 { Some(42i32) } +// ``` +// -> +// ``` +// fn foo() -> i32 { 42i32 } +// ``` +pub(crate) fn unwrap_option_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let ret_type = ctx.find_node_at_offset::()?; + let parent = ret_type.syntax().parent()?; + let body = match_ast! { + match parent { + ast::Fn(func) => func.body()?, + ast::ClosureExpr(closure) => match closure.body()? { + Expr::BlockExpr(block) => block, + // closures require a block when a return type is specified + _ => return None, + }, + _ => return None, + } + }; + + let type_ref = &ret_type.ty()?; + let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { + return None; + }; + let option_enum = + FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_option_Option()?; + if ret_enum != option_enum { + return None; + } + + let ok_type = unwrap_option_type(type_ref)?; + + acc.add( + AssistId("unwrap_option_return_type", AssistKind::RefactorRewrite), + "Unwrap Option return type", + type_ref.syntax().text_range(), + |builder| { + let body = ast::Expr::BlockExpr(body); + + let mut exprs_to_unwrap = Vec::new(); + let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); + walk_expr(&body, &mut |expr| { + if let Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); + } + } + }); + for_each_tail_expr(&body, tail_cb); + + let is_unit_type = is_unit_type(&ok_type); + if is_unit_type { + let mut text_range = ret_type.syntax().text_range(); + + if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { + if token.kind() == SyntaxKind::WHITESPACE { + text_range = TextRange::new(text_range.start(), token.text_range().end()); + } + } + + builder.delete(text_range); + } else { + builder.replace(type_ref.syntax().text_range(), ok_type.syntax().text()); + } + + for ret_expr_arg in exprs_to_unwrap { + let ret_expr_str = ret_expr_arg.to_string(); + if ret_expr_str.starts_with("Some(") { + let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast); + if let Some(arg_list) = arg_list { + if is_unit_type { + match ret_expr_arg.syntax().prev_sibling_or_token() { + // Useful to delete the entire line without leaving trailing whitespaces + Some(whitespace) => { + let new_range = TextRange::new( + whitespace.text_range().start(), + ret_expr_arg.syntax().text_range().end(), + ); + builder.delete(new_range); + } + None => { + builder.delete(ret_expr_arg.syntax().text_range()); + } + } + } else { + builder.replace( + ret_expr_arg.syntax().text_range(), + arg_list.args().join(", "), + ); + } + } + } else if ret_expr_str == "None" { + builder.replace(ret_expr_arg.syntax().text_range(), "()"); + } + } + }, + ) +} + +fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { + match e { + Expr::BreakExpr(break_expr) => { + if let Some(break_expr_arg) = break_expr.expr() { + for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) + } + } + Expr::ReturnExpr(_) => { + // all return expressions have already been handled by the walk loop + } + e => acc.push(e.clone()), + } +} + +// Tries to extract `T` from `Option`. +fn unwrap_option_type(ty: &ast::Type) -> Option { + let ast::Type::PathType(path_ty) = ty else { + return None; + }; + let path = path_ty.path()?; + let segment = path.first_segment()?; + let generic_arg_list = segment.generic_arg_list()?; + let generic_args: Vec<_> = generic_arg_list.generic_args().collect(); + let ast::GenericArg::TypeArg(some_type) = generic_args.first()? else { + return None; + }; + some_type.ty() +} + +fn is_unit_type(ty: &ast::Type) -> bool { + let ast::Type::TupleType(tuple) = ty else { return false }; + tuple.fields().next().is_none() +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn unwrap_option_return_type_simple() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + return Some(42i32); +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_unit_type() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option<()$0> { + Some(()) +} +"#, + r#" +fn foo() { +} +"#, + ); + + // Unformatted return type + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option<()$0>{ + Some(()) +} +"#, + r#" +fn foo() { +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_none() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + if true { + Some(42) + } else { + None + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42 + } else { + () + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_ending_with_parent() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + if true { + Some(42) + } else { + foo() + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42 + } else { + foo() + } +} +"#, + ); + } + + #[test] + fn unwrap_return_type_break_split_tail() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + loop { + break if true { + Some(1) + } else { + Some(0) + }; + } +} +"#, + r#" +fn foo() -> i32 { + loop { + break if true { + 1 + } else { + 0 + }; + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> Option { + let test = "test"; + return Some(42i32); + }; +} +"#, + r#" +fn foo() { + || -> i32 { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_bad_cursor() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> i32 { + let test = "test";$0 + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_bad_cursor_closure() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> i32 { + let test = "test";$0 + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_closure_non_block() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { || -> i$032 3; } +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_already_not_option_std() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> i32$0 { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_already_not_option_closure() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> i32$0 { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() ->$0 Option { + let test = "test"; + Some(42i32) +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + 42i32 +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || ->$0 Option { + let test = "test"; + Some(42i32) + }; +} +"#, + r#" +fn foo() { + || -> i32 { + let test = "test"; + 42i32 + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_only() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { Some(42i32) } +"#, + r#" +fn foo() -> i32 { 42i32 } +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option$0 { + if true { + Some(42i32) + } else { + Some(24i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42i32 + } else { + 24i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_without_block_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> Option$0 { + if true { + Some(42i32) + } else { + Some(24i32) + } + }; +} +"#, + r#" +fn foo() { + || -> i32 { + if true { + 42i32 + } else { + 24i32 + } + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_nested_if() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option$0 { + if true { + if false { + Some(1) + } else { + Some(2) + } + } else { + Some(24i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + if false { + 1 + } else { + 2 + } + } else { + 24i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_await() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +async fn foo() -> Option { + if true { + if false { + Some(1.await) + } else { + Some(2.await) + } + } else { + Some(24i32.await) + } +} +"#, + r#" +async fn foo() -> i32 { + if true { + if false { + 1.await + } else { + 2.await + } + } else { + 24i32.await + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_array() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option<[i32; 3]$0> { Some([1, 2, 3]) } +"#, + r#" +fn foo() -> [i32; 3] { [1, 2, 3] } +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_cast() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -$0> Option { + if true { + if false { + Some(1 as i32) + } else { + Some(2 as i32) + } + } else { + Some(24 as i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + if false { + 1 as i32 + } else { + 2 as i32 + } + } else { + 24 as i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_match() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => Some(42i32), + _ => Some(24i32), + } +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + match my_var { + 5 => 42i32, + _ => 24i32, + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_loop_with_tail() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + loop { + println!("test"); + 5 + } + Some(my_var) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + loop { + println!("test"); + 5 + } + my_var +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_loop_in_let_stmt() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = let x = loop { + break 1; + }; + Some(my_var) +} +"#, + r#" +fn foo() -> i32 { + let my_var = let x = loop { + break 1; + }; + my_var +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_match_return_expr() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option$0 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return Some(24i32), + }; + Some(res) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return 24i32, + }; + res +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return Some(24i32); + }; + Some(res) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return 24i32; + }; + res +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_match_deeper() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => { + if true { + Some(42i32) + } else { + Some(25i32) + } + }, + _ => { + let test = "test"; + if test == "test" { + return Some(bar()); + } + Some(53i32) + }, + } +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + match my_var { + 5 => { + if true { + 42i32 + } else { + 25i32 + } + }, + _ => { + let test = "test"; + if test == "test" { + return bar(); + } + 53i32 + }, + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_early_return() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + Some(53i32) +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + if test == "test" { + return 24i32; + } + 53i32 +} +"#, + ); + } + + #[test] + fn wrap_return_in_tail_position() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(num: i32) -> $0Option { + return Some(num) +} +"#, + r#" +fn foo(num: i32) -> i32 { + return num +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + let t = None; + + Some(t.unwrap_or_else(|| the_field)) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return 99; + } else { + return 0; + } + } + let t = None; + + t.unwrap_or_else(|| the_field) +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_weird_forms() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + let mut i = 0; + loop { + if i == 1 { + break Some(55); + } + i += 1; + } +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + if test == "test" { + return 24i32; + } + let mut i = 0; + loop { + if i == 1 { + break 55; + } + i += 1; + } +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return Some(55u32); + } + i += 3; + } + match i { + 5 => return Some(99), + _ => return Some(0), + }; + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return 55u32; + } + i += 3; + } + match i { + 5 => return 99, + _ => return 0, + }; + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return Some(99), + _ => return Some(0), + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return 99, + _ => return 0, + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99) + } else { + return Some(0) + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99 + } else { + return 0 + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_nested_type() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option, result +fn foo() -> Option> { + Some(Ok(42)) +} +"#, + r#" +fn foo() -> Result { + Ok(42) +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option, result +fn foo() -> Option, ()>> { + Some(Err()) +} +"#, + r#" +fn foo() -> Result, ()> { + Err() +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option, result, iterators +fn foo() -> Option$0> { + Some(Some(42).into_iter()) +} +"#, + r#" +fn foo() -> impl Iterator { + Some(42).into_iter() +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs new file mode 100644 index 0000000000000..90cfc2ef17c74 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs @@ -0,0 +1,1173 @@ +use std::iter; + +use hir::HasSource; +use ide_db::{ + famous_defs::FamousDefs, + syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, +}; +use itertools::Itertools; +use syntax::{ + ast::{self, make, Expr, HasGenericParams}, + match_ast, ted, AstNode, ToSmolStr, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: wrap_return_type_in_option +// +// Wrap the function's return type into Option. +// +// ``` +// # //- minicore: option +// fn foo() -> i32$0 { 42i32 } +// ``` +// -> +// ``` +// fn foo() -> Option { Some(42i32) } +// ``` +pub(crate) fn wrap_return_type_in_option(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let ret_type = ctx.find_node_at_offset::()?; + let parent = ret_type.syntax().parent()?; + let body = match_ast! { + match parent { + ast::Fn(func) => func.body()?, + ast::ClosureExpr(closure) => match closure.body()? { + Expr::BlockExpr(block) => block, + // closures require a block when a return type is specified + _ => return None, + }, + _ => return None, + } + }; + + let type_ref = &ret_type.ty()?; + let core_option = + FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_option_Option()?; + + let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); + if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_option) { + // The return type is already wrapped in an Option + cov_mark::hit!(wrap_return_type_in_option_simple_return_type_already_option); + return None; + } + + acc.add( + AssistId("wrap_return_type_in_option", AssistKind::RefactorRewrite), + "Wrap return type in Option", + type_ref.syntax().text_range(), + |edit| { + let new_option_ty = option_type(ctx, &core_option, type_ref).clone_for_update(); + let body = edit.make_mut(ast::Expr::BlockExpr(body)); + + let mut exprs_to_wrap = Vec::new(); + let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); + walk_expr(&body, &mut |expr| { + if let Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); + } + } + }); + for_each_tail_expr(&body, tail_cb); + + for ret_expr_arg in exprs_to_wrap { + let some_wrapped = make::expr_call( + make::expr_path(make::ext::ident_path("Some")), + make::arg_list(iter::once(ret_expr_arg.clone())), + ) + .clone_for_update(); + ted::replace(ret_expr_arg.syntax(), some_wrapped.syntax()); + } + + let old_option_ty = edit.make_mut(type_ref.clone()); + ted::replace(old_option_ty.syntax(), new_option_ty.syntax()); + }, + ) +} + +fn option_type( + ctx: &AssistContext<'_>, + core_option: &hir::Enum, + ret_type: &ast::Type, +) -> ast::Type { + // Try to find an Option type alias in the current scope (shadowing the default). + let option_path = hir::ModPath::from_segments( + hir::PathKind::Plain, + iter::once(hir::Name::new_symbol_root(hir::sym::Option.clone())), + ); + let alias = ctx.sema.resolve_mod_path(ret_type.syntax(), &option_path).and_then(|def| { + def.filter_map(|def| match def.as_module_def()? { + hir::ModuleDef::TypeAlias(alias) => { + let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?; + (&enum_ty == core_option).then_some(alias) + } + _ => None, + }) + .find_map(|alias| { + let mut inserted_ret_type = false; + let generic_params = alias + .source(ctx.db())? + .value + .generic_param_list()? + .generic_params() + .map(|param| match param { + // Replace the very first type parameter with the functions return type. + ast::GenericParam::TypeParam(_) if !inserted_ret_type => { + inserted_ret_type = true; + ret_type.to_smolstr() + } + ast::GenericParam::LifetimeParam(_) => make::lifetime("'_").to_smolstr(), + _ => make::ty_placeholder().to_smolstr(), + }) + .join(", "); + + let name = alias.name(ctx.db()); + let name = name.as_str(); + Some(make::ty(&format!("{name}<{generic_params}>"))) + }) + }); + // If there is no applicable alias in scope use the default Option type. + alias.unwrap_or_else(|| make::ext::ty_option(ret_type.clone())) +} + +fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { + match e { + Expr::BreakExpr(break_expr) => { + if let Some(break_expr_arg) = break_expr.expr() { + for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) + } + } + Expr::ReturnExpr(_) => { + // all return expressions have already been handled by the walk loop + } + e => acc.push(e.clone()), + } +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn wrap_return_type_in_option_simple() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i3$02 { + let test = "test"; + return 42i32; +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_break_split_tail() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i3$02 { + loop { + break if true { + 1 + } else { + 0 + }; + } +} +"#, + r#" +fn foo() -> Option { + loop { + break if true { + Some(1) + } else { + Some(0) + }; + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> i32$0 { + let test = "test"; + return 42i32; + }; +} +"#, + r#" +fn foo() { + || -> Option { + let test = "test"; + return Some(42i32); + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_bad_cursor() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32 { + let test = "test";$0 + return 42i32; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_bad_cursor_closure() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> i32 { + let test = "test";$0 + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_closure_non_block() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { || -> i$032 3; } +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_already_option_std() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> core::option::Option { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_already_option() { + cov_mark::check!(wrap_return_type_in_option_simple_return_type_already_option); + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_already_option_closure() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> Option { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_cursor() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> $0i32 { + let test = "test"; + return 42i32; +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() ->$0 i32 { + let test = "test"; + 42i32 +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + Some(42i32) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || ->$0 i32 { + let test = "test"; + 42i32 + }; +} +"#, + r#" +fn foo() { + || -> Option { + let test = "test"; + Some(42i32) + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_only() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { 42i32 } +"#, + r#" +fn foo() -> Option { Some(42i32) } +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + if true { + 42i32 + } else { + 24i32 + } +} +"#, + r#" +fn foo() -> Option { + if true { + Some(42i32) + } else { + Some(24i32) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_without_block_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> i32$0 { + if true { + 42i32 + } else { + 24i32 + } + }; +} +"#, + r#" +fn foo() { + || -> Option { + if true { + Some(42i32) + } else { + Some(24i32) + } + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_nested_if() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + if true { + if false { + 1 + } else { + 2 + } + } else { + 24i32 + } +} +"#, + r#" +fn foo() -> Option { + if true { + if false { + Some(1) + } else { + Some(2) + } + } else { + Some(24i32) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_await() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +async fn foo() -> i$032 { + if true { + if false { + 1.await + } else { + 2.await + } + } else { + 24i32.await + } +} +"#, + r#" +async fn foo() -> Option { + if true { + if false { + Some(1.await) + } else { + Some(2.await) + } + } else { + Some(24i32.await) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_array() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> [i32;$0 3] { [1, 2, 3] } +"#, + r#" +fn foo() -> Option<[i32; 3]> { Some([1, 2, 3]) } +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_cast() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -$0> i32 { + if true { + if false { + 1 as i32 + } else { + 2 as i32 + } + } else { + 24 as i32 + } +} +"#, + r#" +fn foo() -> Option { + if true { + if false { + Some(1 as i32) + } else { + Some(2 as i32) + } + } else { + Some(24 as i32) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_match() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + match my_var { + 5 => 42i32, + _ => 24i32, + } +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => Some(42i32), + _ => Some(24i32), + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_loop_with_tail() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + loop { + println!("test"); + 5 + } + my_var +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + loop { + println!("test"); + 5 + } + Some(my_var) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_loop_in_let_stmt() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = let x = loop { + break 1; + }; + my_var +} +"#, + r#" +fn foo() -> Option { + let my_var = let x = loop { + break 1; + }; + Some(my_var) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_match_return_expr() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return 24i32, + }; + res +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return Some(24i32), + }; + Some(res) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return 24i32; + }; + res +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return Some(24i32); + }; + Some(res) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_match_deeper() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + match my_var { + 5 => { + if true { + 42i32 + } else { + 25i32 + } + }, + _ => { + let test = "test"; + if test == "test" { + return bar(); + } + 53i32 + }, + } +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => { + if true { + Some(42i32) + } else { + Some(25i32) + } + }, + _ => { + let test = "test"; + if test == "test" { + return Some(bar()); + } + Some(53i32) + }, + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_early_return() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i$032 { + let test = "test"; + if test == "test" { + return 24i32; + } + 53i32 +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + Some(53i32) +} +"#, + ); + } + + #[test] + fn wrap_return_in_tail_position() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(num: i32) -> $0i32 { + return num +} +"#, + r#" +fn foo(num: i32) -> Option { + return Some(num) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) ->$0 u32 { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u32$0 { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return 99; + } else { + return 0; + } + } + let t = None; + + t.unwrap_or_else(|| the_field) +} +"#, + r#" +fn foo(the_field: u32) -> Option { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + let t = None; + + Some(t.unwrap_or_else(|| the_field)) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_weird_forms() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let test = "test"; + if test == "test" { + return 24i32; + } + let mut i = 0; + loop { + if i == 1 { + break 55; + } + i += 1; + } +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + let mut i = 0; + loop { + if i == 1 { + break Some(55); + } + i += 1; + } +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u32$0 { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return 55u32; + } + i += 3; + } + match i { + 5 => return 99, + _ => return 0, + }; + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return Some(55u32); + } + i += 3; + } + match i { + 5 => return Some(99), + _ => return Some(0), + }; + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u3$02 { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return 99, + _ => return 0, + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return Some(99), + _ => return Some(0), + } + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u32$0 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99 + } else { + return 0 + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99) + } else { + return Some(0) + } + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> $0u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_option_type() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +type Option = core::option::Option; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +type Option = core::option::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +type Option2 = core::option::Option; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +type Option2 = core::option::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_imported_local_option_type() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::Option; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::*; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::*; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_option_type_from_function_body() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i3$02 { + type Option = core::option::Option; + 0 +} +"#, + r#" +fn foo() -> Option { + type Option = core::option::Option; + Some(0) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_option_type_already_using_alias() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +pub type Option = core::option::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + } +} 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 c98655b423029..63a3fec3f41d5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -223,8 +223,10 @@ mod handlers { mod unnecessary_async; mod unqualify_method_call; mod unwrap_block; + mod unwrap_option_return_type; mod unwrap_result_return_type; mod unwrap_tuple; + mod wrap_return_type_in_option; mod wrap_return_type_in_result; mod wrap_unwrap_cfg_attr; @@ -355,9 +357,11 @@ mod handlers { unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, unwrap_block::unwrap_block, + unwrap_option_return_type::unwrap_option_return_type, unwrap_result_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, + wrap_return_type_in_option::wrap_return_type_in_option, wrap_return_type_in_result::wrap_return_type_in_result, 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 48e12a8107353..933d45d750832 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 @@ -3264,6 +3264,20 @@ fn foo() { ) } +#[test] +fn doctest_unwrap_option_return_type() { + check_doc_test( + "unwrap_option_return_type", + r#####" +//- minicore: option +fn foo() -> Option$0 { Some(42i32) } +"#####, + r#####" +fn foo() -> i32 { 42i32 } +"#####, + ) +} + #[test] fn doctest_unwrap_result_return_type() { check_doc_test( @@ -3297,6 +3311,20 @@ fn main() { ) } +#[test] +fn doctest_wrap_return_type_in_option() { + check_doc_test( + "wrap_return_type_in_option", + r#####" +//- minicore: option +fn foo() -> i32$0 { 42i32 } +"#####, + r#####" +fn foo() -> Option { Some(42i32) } +"#####, + ) +} + #[test] fn doctest_wrap_return_type_in_result() { check_doc_test( From 2af15d2ffdf52480ca3955e82535979f1b80e8e0 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 15 Oct 2024 08:33:14 +0200 Subject: [PATCH 02/32] line-index method to allow clamping column to line length Part of #18240 --- .../rust-analyzer/lib/line-index/Cargo.toml | 2 +- .../rust-analyzer/lib/line-index/src/lib.rs | 8 +++++++ .../rust-analyzer/lib/line-index/src/tests.rs | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/lib/line-index/Cargo.toml b/src/tools/rust-analyzer/lib/line-index/Cargo.toml index 8ae4954dd0de9..14196ba3d0973 100644 --- a/src/tools/rust-analyzer/lib/line-index/Cargo.toml +++ b/src/tools/rust-analyzer/lib/line-index/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "line-index" -version = "0.1.1" +version = "0.1.2" description = "Maps flat `TextSize` offsets to/from `(line, column)` representation." license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/line-index" diff --git a/src/tools/rust-analyzer/lib/line-index/src/lib.rs b/src/tools/rust-analyzer/lib/line-index/src/lib.rs index 66875e25242b5..6f0455ee98bad 100644 --- a/src/tools/rust-analyzer/lib/line-index/src/lib.rs +++ b/src/tools/rust-analyzer/lib/line-index/src/lib.rs @@ -177,6 +177,14 @@ impl LineIndex { Some(LineCol { line: line_col.line, col }) } + /// Returns the given line's range. + pub fn line(&self, line: u32) -> Option { + let start = self.start_offset(line as usize)?; + let next_newline = self.newlines.get(line as usize).copied().unwrap_or(self.len); + let line_length = next_newline - start; + Some(TextRange::new(start, start + line_length)) + } + /// Given a range [start, end), returns a sorted iterator of non-empty ranges [start, x1), [x1, /// x2), ..., [xn, end) where all the xi, which are positions of newlines, are inside the range /// [start, end). diff --git a/src/tools/rust-analyzer/lib/line-index/src/tests.rs b/src/tools/rust-analyzer/lib/line-index/src/tests.rs index 57fad1dfc0571..f2bb04aec3230 100644 --- a/src/tools/rust-analyzer/lib/line-index/src/tests.rs +++ b/src/tools/rust-analyzer/lib/line-index/src/tests.rs @@ -195,3 +195,26 @@ fn test_every_chars() { } } } + +#[test] +fn test_line() { + use text_size::TextRange; + + macro_rules! validate { + ($text:expr, $line:expr, $expected_start:literal .. $expected_end:literal) => { + let line_index = LineIndex::new($text); + assert_eq!( + line_index.line($line), + Some(TextRange::new( + TextSize::from($expected_start), + TextSize::from($expected_end) + )) + ); + }; + } + + validate!("", 0, 0..0); + validate!("\n", 1, 1..1); + validate!("\nabc", 1, 1..4); + validate!("\nabc\ndef", 1, 1..5); +} From 7c2373e89706c6f08f1b594785973d127d250597 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:04:28 -0400 Subject: [PATCH 03/32] Re-use code for wrapping/unwrapping return types --- .../src/handlers/unwrap_option_return_type.rs | 1143 --------- .../src/handlers/unwrap_result_return_type.rs | 1115 --------- .../src/handlers/unwrap_return_type.rs | 2159 +++++++++++++++++ ..._type_in_result.rs => wrap_return_type.rs} | 1189 ++++++++- .../handlers/wrap_return_type_in_option.rs | 1173 --------- .../crates/ide-assists/src/lib.rs | 14 +- 6 files changed, 3305 insertions(+), 3488 deletions(-) delete mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs delete mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs rename src/tools/rust-analyzer/crates/ide-assists/src/handlers/{wrap_return_type_in_result.rs => wrap_return_type.rs} (51%) delete mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs deleted file mode 100644 index 8dc40842406ba..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_option_return_type.rs +++ /dev/null @@ -1,1143 +0,0 @@ -use ide_db::{ - famous_defs::FamousDefs, - syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, -}; -use itertools::Itertools; -use syntax::{ - ast::{self, Expr, HasGenericArgs}, - match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, -}; - -use crate::{AssistContext, AssistId, AssistKind, Assists}; - -// Assist: unwrap_option_return_type -// -// Unwrap the function's return type. -// -// ``` -// # //- minicore: option -// fn foo() -> Option$0 { Some(42i32) } -// ``` -// -> -// ``` -// fn foo() -> i32 { 42i32 } -// ``` -pub(crate) fn unwrap_option_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let ret_type = ctx.find_node_at_offset::()?; - let parent = ret_type.syntax().parent()?; - let body = match_ast! { - match parent { - ast::Fn(func) => func.body()?, - ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, - // closures require a block when a return type is specified - _ => return None, - }, - _ => return None, - } - }; - - let type_ref = &ret_type.ty()?; - let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { - return None; - }; - let option_enum = - FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_option_Option()?; - if ret_enum != option_enum { - return None; - } - - let ok_type = unwrap_option_type(type_ref)?; - - acc.add( - AssistId("unwrap_option_return_type", AssistKind::RefactorRewrite), - "Unwrap Option return type", - type_ref.syntax().text_range(), - |builder| { - let body = ast::Expr::BlockExpr(body); - - let mut exprs_to_unwrap = Vec::new(); - let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } - } - }); - for_each_tail_expr(&body, tail_cb); - - let is_unit_type = is_unit_type(&ok_type); - if is_unit_type { - let mut text_range = ret_type.syntax().text_range(); - - if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { - if token.kind() == SyntaxKind::WHITESPACE { - text_range = TextRange::new(text_range.start(), token.text_range().end()); - } - } - - builder.delete(text_range); - } else { - builder.replace(type_ref.syntax().text_range(), ok_type.syntax().text()); - } - - for ret_expr_arg in exprs_to_unwrap { - let ret_expr_str = ret_expr_arg.to_string(); - if ret_expr_str.starts_with("Some(") { - let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast); - if let Some(arg_list) = arg_list { - if is_unit_type { - match ret_expr_arg.syntax().prev_sibling_or_token() { - // Useful to delete the entire line without leaving trailing whitespaces - Some(whitespace) => { - let new_range = TextRange::new( - whitespace.text_range().start(), - ret_expr_arg.syntax().text_range().end(), - ); - builder.delete(new_range); - } - None => { - builder.delete(ret_expr_arg.syntax().text_range()); - } - } - } else { - builder.replace( - ret_expr_arg.syntax().text_range(), - arg_list.args().join(", "), - ); - } - } - } else if ret_expr_str == "None" { - builder.replace(ret_expr_arg.syntax().text_range(), "()"); - } - } - }, - ) -} - -fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { - match e { - Expr::BreakExpr(break_expr) => { - if let Some(break_expr_arg) = break_expr.expr() { - for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) - } - } - Expr::ReturnExpr(_) => { - // all return expressions have already been handled by the walk loop - } - e => acc.push(e.clone()), - } -} - -// Tries to extract `T` from `Option`. -fn unwrap_option_type(ty: &ast::Type) -> Option { - let ast::Type::PathType(path_ty) = ty else { - return None; - }; - let path = path_ty.path()?; - let segment = path.first_segment()?; - let generic_arg_list = segment.generic_arg_list()?; - let generic_args: Vec<_> = generic_arg_list.generic_args().collect(); - let ast::GenericArg::TypeArg(some_type) = generic_args.first()? else { - return None; - }; - some_type.ty() -} - -fn is_unit_type(ty: &ast::Type) -> bool { - let ast::Type::TupleType(tuple) = ty else { return false }; - tuple.fields().next().is_none() -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; - - use super::*; - - #[test] - fn unwrap_option_return_type_simple() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let test = "test"; - return Some(42i32); -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - return 42i32; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_unit_type() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option<()$0> { - Some(()) -} -"#, - r#" -fn foo() { -} -"#, - ); - - // Unformatted return type - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option<()$0>{ - Some(()) -} -"#, - r#" -fn foo() { -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_none() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - if true { - Some(42) - } else { - None - } -} -"#, - r#" -fn foo() -> i32 { - if true { - 42 - } else { - () - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_ending_with_parent() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - if true { - Some(42) - } else { - foo() - } -} -"#, - r#" -fn foo() -> i32 { - if true { - 42 - } else { - foo() - } -} -"#, - ); - } - - #[test] - fn unwrap_return_type_break_split_tail() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - loop { - break if true { - Some(1) - } else { - Some(0) - }; - } -} -"#, - r#" -fn foo() -> i32 { - loop { - break if true { - 1 - } else { - 0 - }; - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_closure() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() { - || -> Option { - let test = "test"; - return Some(42i32); - }; -} -"#, - r#" -fn foo() { - || -> i32 { - let test = "test"; - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_return_type_bad_cursor() { - check_assist_not_applicable( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> i32 { - let test = "test";$0 - return 42i32; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() { - || -> i32 { - let test = "test";$0 - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_closure_non_block() { - check_assist_not_applicable( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() { || -> i$032 3; } -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_return_type_already_not_option_std() { - check_assist_not_applicable( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> i32$0 { - let test = "test"; - return 42i32; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_return_type_already_not_option_closure() { - check_assist_not_applicable( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() { - || -> i32$0 { - let test = "test"; - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() ->$0 Option { - let test = "test"; - Some(42i32) -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - 42i32 -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_closure() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() { - || ->$0 Option { - let test = "test"; - Some(42i32) - }; -} -"#, - r#" -fn foo() { - || -> i32 { - let test = "test"; - 42i32 - }; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_only() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { Some(42i32) } -"#, - r#" -fn foo() -> i32 { 42i32 } -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_block_like() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option$0 { - if true { - Some(42i32) - } else { - Some(24i32) - } -} -"#, - r#" -fn foo() -> i32 { - if true { - 42i32 - } else { - 24i32 - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_without_block_closure() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() { - || -> Option$0 { - if true { - Some(42i32) - } else { - Some(24i32) - } - }; -} -"#, - r#" -fn foo() { - || -> i32 { - if true { - 42i32 - } else { - 24i32 - } - }; -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_nested_if() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option$0 { - if true { - if false { - Some(1) - } else { - Some(2) - } - } else { - Some(24i32) - } -} -"#, - r#" -fn foo() -> i32 { - if true { - if false { - 1 - } else { - 2 - } - } else { - 24i32 - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_await() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -async fn foo() -> Option { - if true { - if false { - Some(1.await) - } else { - Some(2.await) - } - } else { - Some(24i32.await) - } -} -"#, - r#" -async fn foo() -> i32 { - if true { - if false { - 1.await - } else { - 2.await - } - } else { - 24i32.await - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_array() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option<[i32; 3]$0> { Some([1, 2, 3]) } -"#, - r#" -fn foo() -> [i32; 3] { [1, 2, 3] } -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_cast() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -$0> Option { - if true { - if false { - Some(1 as i32) - } else { - Some(2 as i32) - } - } else { - Some(24 as i32) - } -} -"#, - r#" -fn foo() -> i32 { - if true { - if false { - 1 as i32 - } else { - 2 as i32 - } - } else { - 24 as i32 - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_block_like_match() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let my_var = 5; - match my_var { - 5 => Some(42i32), - _ => Some(24i32), - } -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - match my_var { - 5 => 42i32, - _ => 24i32, - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_loop_with_tail() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let my_var = 5; - loop { - println!("test"); - 5 - } - Some(my_var) -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - loop { - println!("test"); - 5 - } - my_var -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_loop_in_let_stmt() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let my_var = let x = loop { - break 1; - }; - Some(my_var) -} -"#, - r#" -fn foo() -> i32 { - let my_var = let x = loop { - break 1; - }; - my_var -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_block_like_match_return_expr() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option$0 { - let my_var = 5; - let res = match my_var { - 5 => 42i32, - _ => return Some(24i32), - }; - Some(res) -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - let res = match my_var { - 5 => 42i32, - _ => return 24i32, - }; - res -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let my_var = 5; - let res = if my_var == 5 { - 42i32 - } else { - return Some(24i32); - }; - Some(res) -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - let res = if my_var == 5 { - 42i32 - } else { - return 24i32; - }; - res -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_block_like_match_deeper() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let my_var = 5; - match my_var { - 5 => { - if true { - Some(42i32) - } else { - Some(25i32) - } - }, - _ => { - let test = "test"; - if test == "test" { - return Some(bar()); - } - Some(53i32) - }, - } -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - match my_var { - 5 => { - if true { - 42i32 - } else { - 25i32 - } - }, - _ => { - let test = "test"; - if test == "test" { - return bar(); - } - 53i32 - }, - } -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_tail_block_like_early_return() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let test = "test"; - if test == "test" { - return Some(24i32); - } - Some(53i32) -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - if test == "test" { - return 24i32; - } - 53i32 -} -"#, - ); - } - - #[test] - fn wrap_return_in_tail_position() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(num: i32) -> $0Option { - return Some(num) -} -"#, - r#" -fn foo(num: i32) -> i32 { - return num -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_closure() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(the_field: u32) -> Option { - let true_closure = || { return true; }; - if the_field < 5 { - let mut i = 0; - if true_closure() { - return Some(99); - } else { - return Some(0); - } - } - Some(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - let true_closure = || { return true; }; - if the_field < 5 { - let mut i = 0; - if true_closure() { - return 99; - } else { - return 0; - } - } - the_field -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(the_field: u32) -> Option { - let true_closure = || { - return true; - }; - if the_field < 5 { - let mut i = 0; - - - if true_closure() { - return Some(99); - } else { - return Some(0); - } - } - let t = None; - - Some(t.unwrap_or_else(|| the_field)) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - let true_closure = || { - return true; - }; - if the_field < 5 { - let mut i = 0; - - - if true_closure() { - return 99; - } else { - return 0; - } - } - let t = None; - - t.unwrap_or_else(|| the_field) -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_simple_with_weird_forms() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo() -> Option { - let test = "test"; - if test == "test" { - return Some(24i32); - } - let mut i = 0; - loop { - if i == 1 { - break Some(55); - } - i += 1; - } -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - if test == "test" { - return 24i32; - } - let mut i = 0; - loop { - if i == 1 { - break 55; - } - i += 1; - } -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - loop { - if i > 5 { - return Some(55u32); - } - i += 3; - } - match i { - 5 => return Some(99), - _ => return Some(0), - }; - } - Some(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - loop { - if i > 5 { - return 55u32; - } - i += 3; - } - match i { - 5 => return 99, - _ => return 0, - }; - } - the_field -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - match i { - 5 => return Some(99), - _ => return Some(0), - } - } - Some(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - match i { - 5 => return 99, - _ => return 0, - } - } - the_field -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return Some(99) - } else { - return Some(0) - } - } - Some(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return 99 - } else { - return 0 - } - } - the_field -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return Some(99); - } else { - return Some(0); - } - } - Some(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return 99; - } else { - return 0; - } - } - the_field -} -"#, - ); - } - - #[test] - fn unwrap_option_return_type_nested_type() { - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option, result -fn foo() -> Option> { - Some(Ok(42)) -} -"#, - r#" -fn foo() -> Result { - Ok(42) -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option, result -fn foo() -> Option, ()>> { - Some(Err()) -} -"#, - r#" -fn foo() -> Result, ()> { - Err() -} -"#, - ); - - check_assist( - unwrap_option_return_type, - r#" -//- minicore: option, result, iterators -fn foo() -> Option$0> { - Some(Some(42).into_iter()) -} -"#, - r#" -fn foo() -> impl Iterator { - Some(42).into_iter() -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs deleted file mode 100644 index a1987247cb63b..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs +++ /dev/null @@ -1,1115 +0,0 @@ -use ide_db::{ - famous_defs::FamousDefs, - syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, -}; -use itertools::Itertools; -use syntax::{ - ast::{self, Expr, HasGenericArgs}, - match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, -}; - -use crate::{AssistContext, AssistId, AssistKind, Assists}; - -// Assist: unwrap_result_return_type -// -// Unwrap the function's return type. -// -// ``` -// # //- minicore: result -// fn foo() -> Result$0 { Ok(42i32) } -// ``` -// -> -// ``` -// fn foo() -> i32 { 42i32 } -// ``` -pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let ret_type = ctx.find_node_at_offset::()?; - let parent = ret_type.syntax().parent()?; - let body = match_ast! { - match parent { - ast::Fn(func) => func.body()?, - ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, - // closures require a block when a return type is specified - _ => return None, - }, - _ => return None, - } - }; - - let type_ref = &ret_type.ty()?; - let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { - return None; - }; - let result_enum = - FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?; - if ret_enum != result_enum { - return None; - } - - let ok_type = unwrap_result_type(type_ref)?; - - acc.add( - AssistId("unwrap_result_return_type", AssistKind::RefactorRewrite), - "Unwrap Result return type", - type_ref.syntax().text_range(), - |builder| { - let body = ast::Expr::BlockExpr(body); - - let mut exprs_to_unwrap = Vec::new(); - let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } - } - }); - for_each_tail_expr(&body, tail_cb); - - let is_unit_type = is_unit_type(&ok_type); - if is_unit_type { - let mut text_range = ret_type.syntax().text_range(); - - if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { - if token.kind() == SyntaxKind::WHITESPACE { - text_range = TextRange::new(text_range.start(), token.text_range().end()); - } - } - - builder.delete(text_range); - } else { - builder.replace(type_ref.syntax().text_range(), ok_type.syntax().text()); - } - - for ret_expr_arg in exprs_to_unwrap { - let ret_expr_str = ret_expr_arg.to_string(); - if ret_expr_str.starts_with("Ok(") || ret_expr_str.starts_with("Err(") { - let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast); - if let Some(arg_list) = arg_list { - if is_unit_type { - match ret_expr_arg.syntax().prev_sibling_or_token() { - // Useful to delete the entire line without leaving trailing whitespaces - Some(whitespace) => { - let new_range = TextRange::new( - whitespace.text_range().start(), - ret_expr_arg.syntax().text_range().end(), - ); - builder.delete(new_range); - } - None => { - builder.delete(ret_expr_arg.syntax().text_range()); - } - } - } else { - builder.replace( - ret_expr_arg.syntax().text_range(), - arg_list.args().join(", "), - ); - } - } - } - } - }, - ) -} - -fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { - match e { - Expr::BreakExpr(break_expr) => { - if let Some(break_expr_arg) = break_expr.expr() { - for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) - } - } - Expr::ReturnExpr(_) => { - // all return expressions have already been handled by the walk loop - } - e => acc.push(e.clone()), - } -} - -// Tries to extract `T` from `Result`. -fn unwrap_result_type(ty: &ast::Type) -> Option { - let ast::Type::PathType(path_ty) = ty else { - return None; - }; - let path = path_ty.path()?; - let segment = path.first_segment()?; - let generic_arg_list = segment.generic_arg_list()?; - let generic_args: Vec<_> = generic_arg_list.generic_args().collect(); - let ast::GenericArg::TypeArg(ok_type) = generic_args.first()? else { - return None; - }; - ok_type.ty() -} - -fn is_unit_type(ty: &ast::Type) -> bool { - let ast::Type::TupleType(tuple) = ty else { return false }; - tuple.fields().next().is_none() -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; - - use super::*; - - #[test] - fn unwrap_result_return_type_simple() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let test = "test"; - return Ok(42i32); -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - return 42i32; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_unit_type() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result<(), Box> { - Ok(()) -} -"#, - r#" -fn foo() { -} -"#, - ); - - // Unformatted return type - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result<(), Box>{ - Ok(()) -} -"#, - r#" -fn foo() { -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_ending_with_parent() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result> { - if true { - Ok(42) - } else { - foo() - } -} -"#, - r#" -fn foo() -> i32 { - if true { - 42 - } else { - foo() - } -} -"#, - ); - } - - #[test] - fn unwrap_return_type_break_split_tail() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - loop { - break if true { - Ok(1) - } else { - Ok(0) - }; - } -} -"#, - r#" -fn foo() -> i32 { - loop { - break if true { - 1 - } else { - 0 - }; - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_closure() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() { - || -> Result { - let test = "test"; - return Ok(42i32); - }; -} -"#, - r#" -fn foo() { - || -> i32 { - let test = "test"; - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_return_type_bad_cursor() { - check_assist_not_applicable( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> i32 { - let test = "test";$0 - return 42i32; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() { - || -> i32 { - let test = "test";$0 - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_closure_non_block() { - check_assist_not_applicable( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() { || -> i$032 3; } -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_return_type_already_not_result_std() { - check_assist_not_applicable( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> i32$0 { - let test = "test"; - return 42i32; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_return_type_already_not_result_closure() { - check_assist_not_applicable( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() { - || -> i32$0 { - let test = "test"; - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() ->$0 Result { - let test = "test"; - Ok(42i32) -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - 42i32 -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_closure() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() { - || ->$0 Result { - let test = "test"; - Ok(42i32) - }; -} -"#, - r#" -fn foo() { - || -> i32 { - let test = "test"; - 42i32 - }; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_only() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { Ok(42i32) } -"#, - r#" -fn foo() -> i32 { 42i32 } -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_block_like() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result$0 { - if true { - Ok(42i32) - } else { - Ok(24i32) - } -} -"#, - r#" -fn foo() -> i32 { - if true { - 42i32 - } else { - 24i32 - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_without_block_closure() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() { - || -> Result$0 { - if true { - Ok(42i32) - } else { - Ok(24i32) - } - }; -} -"#, - r#" -fn foo() { - || -> i32 { - if true { - 42i32 - } else { - 24i32 - } - }; -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_nested_if() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result$0 { - if true { - if false { - Ok(1) - } else { - Ok(2) - } - } else { - Ok(24i32) - } -} -"#, - r#" -fn foo() -> i32 { - if true { - if false { - 1 - } else { - 2 - } - } else { - 24i32 - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_await() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -async fn foo() -> Result { - if true { - if false { - Ok(1.await) - } else { - Ok(2.await) - } - } else { - Ok(24i32.await) - } -} -"#, - r#" -async fn foo() -> i32 { - if true { - if false { - 1.await - } else { - 2.await - } - } else { - 24i32.await - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_array() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result<[i32; 3]$0> { Ok([1, 2, 3]) } -"#, - r#" -fn foo() -> [i32; 3] { [1, 2, 3] } -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_cast() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -$0> Result { - if true { - if false { - Ok(1 as i32) - } else { - Ok(2 as i32) - } - } else { - Ok(24 as i32) - } -} -"#, - r#" -fn foo() -> i32 { - if true { - if false { - 1 as i32 - } else { - 2 as i32 - } - } else { - 24 as i32 - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_block_like_match() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let my_var = 5; - match my_var { - 5 => Ok(42i32), - _ => Ok(24i32), - } -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - match my_var { - 5 => 42i32, - _ => 24i32, - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_loop_with_tail() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let my_var = 5; - loop { - println!("test"); - 5 - } - Ok(my_var) -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - loop { - println!("test"); - 5 - } - my_var -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_loop_in_let_stmt() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let my_var = let x = loop { - break 1; - }; - Ok(my_var) -} -"#, - r#" -fn foo() -> i32 { - let my_var = let x = loop { - break 1; - }; - my_var -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_block_like_match_return_expr() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result$0 { - let my_var = 5; - let res = match my_var { - 5 => 42i32, - _ => return Ok(24i32), - }; - Ok(res) -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - let res = match my_var { - 5 => 42i32, - _ => return 24i32, - }; - res -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let my_var = 5; - let res = if my_var == 5 { - 42i32 - } else { - return Ok(24i32); - }; - Ok(res) -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - let res = if my_var == 5 { - 42i32 - } else { - return 24i32; - }; - res -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_block_like_match_deeper() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let my_var = 5; - match my_var { - 5 => { - if true { - Ok(42i32) - } else { - Ok(25i32) - } - }, - _ => { - let test = "test"; - if test == "test" { - return Ok(bar()); - } - Ok(53i32) - }, - } -} -"#, - r#" -fn foo() -> i32 { - let my_var = 5; - match my_var { - 5 => { - if true { - 42i32 - } else { - 25i32 - } - }, - _ => { - let test = "test"; - if test == "test" { - return bar(); - } - 53i32 - }, - } -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_tail_block_like_early_return() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let test = "test"; - if test == "test" { - return Ok(24i32); - } - Ok(53i32) -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - if test == "test" { - return 24i32; - } - 53i32 -} -"#, - ); - } - - #[test] - fn wrap_return_in_tail_position() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(num: i32) -> $0Result { - return Ok(num) -} -"#, - r#" -fn foo(num: i32) -> i32 { - return num -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_closure() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(the_field: u32) -> Result { - let true_closure = || { return true; }; - if the_field < 5 { - let mut i = 0; - if true_closure() { - return Ok(99); - } else { - return Ok(0); - } - } - Ok(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - let true_closure = || { return true; }; - if the_field < 5 { - let mut i = 0; - if true_closure() { - return 99; - } else { - return 0; - } - } - the_field -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(the_field: u32) -> Result { - let true_closure = || { - return true; - }; - if the_field < 5 { - let mut i = 0; - - - if true_closure() { - return Ok(99); - } else { - return Ok(0); - } - } - let t = None; - - Ok(t.unwrap_or_else(|| the_field)) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - let true_closure = || { - return true; - }; - if the_field < 5 { - let mut i = 0; - - - if true_closure() { - return 99; - } else { - return 0; - } - } - let t = None; - - t.unwrap_or_else(|| the_field) -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_simple_with_weird_forms() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo() -> Result { - let test = "test"; - if test == "test" { - return Ok(24i32); - } - let mut i = 0; - loop { - if i == 1 { - break Ok(55); - } - i += 1; - } -} -"#, - r#" -fn foo() -> i32 { - let test = "test"; - if test == "test" { - return 24i32; - } - let mut i = 0; - loop { - if i == 1 { - break 55; - } - i += 1; - } -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(the_field: u32) -> Result { - if the_field < 5 { - let mut i = 0; - loop { - if i > 5 { - return Ok(55u32); - } - i += 3; - } - match i { - 5 => return Ok(99), - _ => return Ok(0), - }; - } - Ok(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - loop { - if i > 5 { - return 55u32; - } - i += 3; - } - match i { - 5 => return 99, - _ => return 0, - }; - } - the_field -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(the_field: u32) -> Result { - if the_field < 5 { - let mut i = 0; - match i { - 5 => return Ok(99), - _ => return Ok(0), - } - } - Ok(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - match i { - 5 => return 99, - _ => return 0, - } - } - the_field -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(the_field: u32) -> Result { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return Ok(99) - } else { - return Ok(0) - } - } - Ok(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return 99 - } else { - return 0 - } - } - the_field -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result -fn foo(the_field: u32) -> Result { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return Ok(99); - } else { - return Ok(0); - } - } - Ok(the_field) -} -"#, - r#" -fn foo(the_field: u32) -> u32 { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return 99; - } else { - return 0; - } - } - the_field -} -"#, - ); - } - - #[test] - fn unwrap_result_return_type_nested_type() { - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result, option -fn foo() -> Result, ()> { - Ok(Some(42)) -} -"#, - r#" -fn foo() -> Option { - Some(42) -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result, option -fn foo() -> Result>, ()> { - Ok(None) -} -"#, - r#" -fn foo() -> Option> { - None -} -"#, - ); - - check_assist( - unwrap_result_return_type, - r#" -//- minicore: result, option, iterators -fn foo() -> Result$0, ()> { - Ok(Some(42).into_iter()) -} -"#, - r#" -fn foo() -> impl Iterator { - Some(42).into_iter() -} -"#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs new file mode 100644 index 0000000000000..b7f873c7798e2 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs @@ -0,0 +1,2159 @@ +use ide_db::{ + famous_defs::FamousDefs, + syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, +}; +use itertools::Itertools; +use syntax::{ + ast::{self, Expr, HasGenericArgs}, + match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: unwrap_option_return_type +// +// Unwrap the function's return type. +// +// ``` +// # //- minicore: option +// fn foo() -> Option$0 { Some(42i32) } +// ``` +// -> +// ``` +// fn foo() -> i32 { 42i32 } +// ``` +pub(crate) fn unwrap_option_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + unwrap_return_type(acc, ctx, UnwrapperKind::Option) +} + +// Assist: unwrap_result_return_type +// +// Unwrap the function's return type. +// +// ``` +// # //- minicore: result +// fn foo() -> Result$0 { Ok(42i32) } +// ``` +// -> +// ``` +// fn foo() -> i32 { 42i32 } +// ``` +pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + unwrap_return_type(acc, ctx, UnwrapperKind::Result) +} + +fn unwrap_return_type( + acc: &mut Assists, + ctx: &AssistContext<'_>, + kind: UnwrapperKind, +) -> Option<()> { + let ret_type = ctx.find_node_at_offset::()?; + let parent = ret_type.syntax().parent()?; + let body = match_ast! { + match parent { + ast::Fn(func) => func.body()?, + ast::ClosureExpr(closure) => match closure.body()? { + Expr::BlockExpr(block) => block, + // closures require a block when a return type is specified + _ => return None, + }, + _ => return None, + } + }; + + let type_ref = &ret_type.ty()?; + let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { + return None; + }; + let core_enum = + kind.core_type(FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()))?; + if ret_enum != core_enum { + return None; + } + + let happy_type = extract_wrapped_type(type_ref)?; + + acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |builder| { + let body = ast::Expr::BlockExpr(body); + + let mut exprs_to_unwrap = Vec::new(); + let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); + walk_expr(&body, &mut |expr| { + if let Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); + } + } + }); + for_each_tail_expr(&body, tail_cb); + + let is_unit_type = is_unit_type(&happy_type); + if is_unit_type { + let mut text_range = ret_type.syntax().text_range(); + + if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { + if token.kind() == SyntaxKind::WHITESPACE { + text_range = TextRange::new(text_range.start(), token.text_range().end()); + } + } + + builder.delete(text_range); + } else { + builder.replace(type_ref.syntax().text_range(), happy_type.syntax().text()); + } + + for ret_expr_arg in exprs_to_unwrap { + let ret_expr_str = ret_expr_arg.to_string(); + + let needs_replacing = match kind { + UnwrapperKind::Option => ret_expr_str.starts_with("Some("), + UnwrapperKind::Result => { + ret_expr_str.starts_with("Ok(") || ret_expr_str.starts_with("Err(") + } + }; + + if needs_replacing { + let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast); + if let Some(arg_list) = arg_list { + if is_unit_type { + match ret_expr_arg.syntax().prev_sibling_or_token() { + // Useful to delete the entire line without leaving trailing whitespaces + Some(whitespace) => { + let new_range = TextRange::new( + whitespace.text_range().start(), + ret_expr_arg.syntax().text_range().end(), + ); + builder.delete(new_range); + } + None => { + builder.delete(ret_expr_arg.syntax().text_range()); + } + } + } else { + builder.replace( + ret_expr_arg.syntax().text_range(), + arg_list.args().join(", "), + ); + } + } + } else if matches!(kind, UnwrapperKind::Option if ret_expr_str == "None") { + builder.replace(ret_expr_arg.syntax().text_range(), "()"); + } + } + }) +} + +enum UnwrapperKind { + Option, + Result, +} + +impl UnwrapperKind { + fn assist_id(&self) -> AssistId { + let s = match self { + UnwrapperKind::Option => "unwrap_option_return_type", + UnwrapperKind::Result => "unwrap_result_return_type", + }; + + AssistId(s, AssistKind::RefactorRewrite) + } + + fn label(&self) -> &'static str { + match self { + UnwrapperKind::Option => "Unwrap Option return type", + UnwrapperKind::Result => "Unwrap Result return type", + } + } + + fn core_type(&self, famous_defs: FamousDefs<'_, '_>) -> Option { + match self { + UnwrapperKind::Option => famous_defs.core_option_Option(), + UnwrapperKind::Result => famous_defs.core_result_Result(), + } + } +} + +fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { + match e { + Expr::BreakExpr(break_expr) => { + if let Some(break_expr_arg) = break_expr.expr() { + for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) + } + } + Expr::ReturnExpr(_) => { + // all return expressions have already been handled by the walk loop + } + e => acc.push(e.clone()), + } +} + +// Tries to extract `T` from `Option` or `Result`. +fn extract_wrapped_type(ty: &ast::Type) -> Option { + let ast::Type::PathType(path_ty) = ty else { + return None; + }; + let path = path_ty.path()?; + let segment = path.first_segment()?; + let generic_arg_list = segment.generic_arg_list()?; + let generic_args: Vec<_> = generic_arg_list.generic_args().collect(); + let ast::GenericArg::TypeArg(happy_type) = generic_args.first()? else { + return None; + }; + happy_type.ty() +} + +fn is_unit_type(ty: &ast::Type) -> bool { + let ast::Type::TupleType(tuple) = ty else { return false }; + tuple.fields().next().is_none() +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn unwrap_option_return_type_simple() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + return Some(42i32); +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_unit_type() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option<()$0> { + Some(()) +} +"#, + r#" +fn foo() { +} +"#, + ); + + // Unformatted return type + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option<()$0>{ + Some(()) +} +"#, + r#" +fn foo() { +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_none() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + if true { + Some(42) + } else { + None + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42 + } else { + () + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_ending_with_parent() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + if true { + Some(42) + } else { + foo() + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42 + } else { + foo() + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_break_split_tail() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + loop { + break if true { + Some(1) + } else { + Some(0) + }; + } +} +"#, + r#" +fn foo() -> i32 { + loop { + break if true { + 1 + } else { + 0 + }; + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> Option { + let test = "test"; + return Some(42i32); + }; +} +"#, + r#" +fn foo() { + || -> i32 { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_bad_cursor() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> i32 { + let test = "test";$0 + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_bad_cursor_closure() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> i32 { + let test = "test";$0 + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_closure_non_block() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { || -> i$032 3; } +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_already_not_option_std() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> i32$0 { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_return_type_already_not_option_closure() { + check_assist_not_applicable( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> i32$0 { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() ->$0 Option { + let test = "test"; + Some(42i32) +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + 42i32 +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || ->$0 Option { + let test = "test"; + Some(42i32) + }; +} +"#, + r#" +fn foo() { + || -> i32 { + let test = "test"; + 42i32 + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_only() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { Some(42i32) } +"#, + r#" +fn foo() -> i32 { 42i32 } +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option$0 { + if true { + Some(42i32) + } else { + Some(24i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42i32 + } else { + 24i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_without_block_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() { + || -> Option$0 { + if true { + Some(42i32) + } else { + Some(24i32) + } + }; +} +"#, + r#" +fn foo() { + || -> i32 { + if true { + 42i32 + } else { + 24i32 + } + }; +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_nested_if() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option$0 { + if true { + if false { + Some(1) + } else { + Some(2) + } + } else { + Some(24i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + if false { + 1 + } else { + 2 + } + } else { + 24i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_await() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +async fn foo() -> Option { + if true { + if false { + Some(1.await) + } else { + Some(2.await) + } + } else { + Some(24i32.await) + } +} +"#, + r#" +async fn foo() -> i32 { + if true { + if false { + 1.await + } else { + 2.await + } + } else { + 24i32.await + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_array() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option<[i32; 3]$0> { Some([1, 2, 3]) } +"#, + r#" +fn foo() -> [i32; 3] { [1, 2, 3] } +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_cast() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -$0> Option { + if true { + if false { + Some(1 as i32) + } else { + Some(2 as i32) + } + } else { + Some(24 as i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + if false { + 1 as i32 + } else { + 2 as i32 + } + } else { + 24 as i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_match() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => Some(42i32), + _ => Some(24i32), + } +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + match my_var { + 5 => 42i32, + _ => 24i32, + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_loop_with_tail() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + loop { + println!("test"); + 5 + } + Some(my_var) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + loop { + println!("test"); + 5 + } + my_var +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_loop_in_let_stmt() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = let x = loop { + break 1; + }; + Some(my_var) +} +"#, + r#" +fn foo() -> i32 { + let my_var = let x = loop { + break 1; + }; + my_var +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_match_return_expr() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option$0 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return Some(24i32), + }; + Some(res) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return 24i32, + }; + res +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return Some(24i32); + }; + Some(res) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return 24i32; + }; + res +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_match_deeper() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => { + if true { + Some(42i32) + } else { + Some(25i32) + } + }, + _ => { + let test = "test"; + if test == "test" { + return Some(bar()); + } + Some(53i32) + }, + } +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + match my_var { + 5 => { + if true { + 42i32 + } else { + 25i32 + } + }, + _ => { + let test = "test"; + if test == "test" { + return bar(); + } + 53i32 + }, + } +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_tail_block_like_early_return() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + Some(53i32) +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + if test == "test" { + return 24i32; + } + 53i32 +} +"#, + ); + } + + #[test] + fn unwrap_option_return_in_tail_position() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(num: i32) -> $0Option { + return Some(num) +} +"#, + r#" +fn foo(num: i32) -> i32 { + return num +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_closure() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + let t = None; + + Some(t.unwrap_or_else(|| the_field)) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return 99; + } else { + return 0; + } + } + let t = None; + + t.unwrap_or_else(|| the_field) +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_simple_with_weird_forms() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + let mut i = 0; + loop { + if i == 1 { + break Some(55); + } + i += 1; + } +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + if test == "test" { + return 24i32; + } + let mut i = 0; + loop { + if i == 1 { + break 55; + } + i += 1; + } +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return Some(55u32); + } + i += 3; + } + match i { + 5 => return Some(99), + _ => return Some(0), + }; + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return 55u32; + } + i += 3; + } + match i { + 5 => return 99, + _ => return 0, + }; + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return Some(99), + _ => return Some(0), + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return 99, + _ => return 0, + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99) + } else { + return Some(0) + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99 + } else { + return 0 + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + ); + } + + #[test] + fn unwrap_option_return_type_nested_type() { + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option, result +fn foo() -> Option> { + Some(Ok(42)) +} +"#, + r#" +fn foo() -> Result { + Ok(42) +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option, result +fn foo() -> Option, ()>> { + Some(Err()) +} +"#, + r#" +fn foo() -> Result, ()> { + Err() +} +"#, + ); + + check_assist( + unwrap_option_return_type, + r#" +//- minicore: option, result, iterators +fn foo() -> Option$0> { + Some(Some(42).into_iter()) +} +"#, + r#" +fn foo() -> impl Iterator { + Some(42).into_iter() +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let test = "test"; + return Ok(42i32); +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_unit_type() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result<(), Box> { + Ok(()) +} +"#, + r#" +fn foo() { +} +"#, + ); + + // Unformatted return type + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result<(), Box>{ + Ok(()) +} +"#, + r#" +fn foo() { +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_ending_with_parent() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result> { + if true { + Ok(42) + } else { + foo() + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42 + } else { + foo() + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_break_split_tail() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + loop { + break if true { + Ok(1) + } else { + Ok(0) + }; + } +} +"#, + r#" +fn foo() -> i32 { + loop { + break if true { + 1 + } else { + 0 + }; + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_closure() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() { + || -> Result { + let test = "test"; + return Ok(42i32); + }; +} +"#, + r#" +fn foo() { + || -> i32 { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_return_type_bad_cursor() { + check_assist_not_applicable( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> i32 { + let test = "test";$0 + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_return_type_bad_cursor_closure() { + check_assist_not_applicable( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() { + || -> i32 { + let test = "test";$0 + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_closure_non_block() { + check_assist_not_applicable( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() { || -> i$032 3; } +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_return_type_already_not_result_std() { + check_assist_not_applicable( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> i32$0 { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_return_type_already_not_result_closure() { + check_assist_not_applicable( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() { + || -> i32$0 { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() ->$0 Result { + let test = "test"; + Ok(42i32) +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + 42i32 +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_closure() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() { + || ->$0 Result { + let test = "test"; + Ok(42i32) + }; +} +"#, + r#" +fn foo() { + || -> i32 { + let test = "test"; + 42i32 + }; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_only() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { Ok(42i32) } +"#, + r#" +fn foo() -> i32 { 42i32 } +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_block_like() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result$0 { + if true { + Ok(42i32) + } else { + Ok(24i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + 42i32 + } else { + 24i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_without_block_closure() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() { + || -> Result$0 { + if true { + Ok(42i32) + } else { + Ok(24i32) + } + }; +} +"#, + r#" +fn foo() { + || -> i32 { + if true { + 42i32 + } else { + 24i32 + } + }; +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_nested_if() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result$0 { + if true { + if false { + Ok(1) + } else { + Ok(2) + } + } else { + Ok(24i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + if false { + 1 + } else { + 2 + } + } else { + 24i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_await() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +async fn foo() -> Result { + if true { + if false { + Ok(1.await) + } else { + Ok(2.await) + } + } else { + Ok(24i32.await) + } +} +"#, + r#" +async fn foo() -> i32 { + if true { + if false { + 1.await + } else { + 2.await + } + } else { + 24i32.await + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_array() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result<[i32; 3]$0> { Ok([1, 2, 3]) } +"#, + r#" +fn foo() -> [i32; 3] { [1, 2, 3] } +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_cast() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -$0> Result { + if true { + if false { + Ok(1 as i32) + } else { + Ok(2 as i32) + } + } else { + Ok(24 as i32) + } +} +"#, + r#" +fn foo() -> i32 { + if true { + if false { + 1 as i32 + } else { + 2 as i32 + } + } else { + 24 as i32 + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_block_like_match() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let my_var = 5; + match my_var { + 5 => Ok(42i32), + _ => Ok(24i32), + } +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + match my_var { + 5 => 42i32, + _ => 24i32, + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_loop_with_tail() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let my_var = 5; + loop { + println!("test"); + 5 + } + Ok(my_var) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + loop { + println!("test"); + 5 + } + my_var +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_loop_in_let_stmt() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let my_var = let x = loop { + break 1; + }; + Ok(my_var) +} +"#, + r#" +fn foo() -> i32 { + let my_var = let x = loop { + break 1; + }; + my_var +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_block_like_match_return_expr() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result$0 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return Ok(24i32), + }; + Ok(res) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return 24i32, + }; + res +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return Ok(24i32); + }; + Ok(res) +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return 24i32; + }; + res +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_block_like_match_deeper() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let my_var = 5; + match my_var { + 5 => { + if true { + Ok(42i32) + } else { + Ok(25i32) + } + }, + _ => { + let test = "test"; + if test == "test" { + return Ok(bar()); + } + Ok(53i32) + }, + } +} +"#, + r#" +fn foo() -> i32 { + let my_var = 5; + match my_var { + 5 => { + if true { + 42i32 + } else { + 25i32 + } + }, + _ => { + let test = "test"; + if test == "test" { + return bar(); + } + 53i32 + }, + } +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_tail_block_like_early_return() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let test = "test"; + if test == "test" { + return Ok(24i32); + } + Ok(53i32) +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + if test == "test" { + return 24i32; + } + 53i32 +} +"#, + ); + } + + #[test] + fn unwrap_result_return_in_tail_position() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(num: i32) -> $0Result { + return Ok(num) +} +"#, + r#" +fn foo(num: i32) -> i32 { + return num +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_closure() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(the_field: u32) -> Result { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return Ok(99); + } else { + return Ok(0); + } + } + Ok(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(the_field: u32) -> Result { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return Ok(99); + } else { + return Ok(0); + } + } + let t = None; + + Ok(t.unwrap_or_else(|| the_field)) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return 99; + } else { + return 0; + } + } + let t = None; + + t.unwrap_or_else(|| the_field) +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_simple_with_weird_forms() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo() -> Result { + let test = "test"; + if test == "test" { + return Ok(24i32); + } + let mut i = 0; + loop { + if i == 1 { + break Ok(55); + } + i += 1; + } +} +"#, + r#" +fn foo() -> i32 { + let test = "test"; + if test == "test" { + return 24i32; + } + let mut i = 0; + loop { + if i == 1 { + break 55; + } + i += 1; + } +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(the_field: u32) -> Result { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return Ok(55u32); + } + i += 3; + } + match i { + 5 => return Ok(99), + _ => return Ok(0), + }; + } + Ok(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return 55u32; + } + i += 3; + } + match i { + 5 => return 99, + _ => return 0, + }; + } + the_field +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(the_field: u32) -> Result { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return Ok(99), + _ => return Ok(0), + } + } + Ok(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return 99, + _ => return 0, + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(the_field: u32) -> Result { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Ok(99) + } else { + return Ok(0) + } + } + Ok(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99 + } else { + return 0 + } + } + the_field +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result +fn foo(the_field: u32) -> Result { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Ok(99); + } else { + return Ok(0); + } + } + Ok(the_field) +} +"#, + r#" +fn foo(the_field: u32) -> u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + ); + } + + #[test] + fn unwrap_result_return_type_nested_type() { + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result, option +fn foo() -> Result, ()> { + Ok(Some(42)) +} +"#, + r#" +fn foo() -> Option { + Some(42) +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result, option +fn foo() -> Result>, ()> { + Ok(None) +} +"#, + r#" +fn foo() -> Option> { + None +} +"#, + ); + + check_assist( + unwrap_result_return_type, + r#" +//- minicore: result, option, iterators +fn foo() -> Result$0, ()> { + Ok(Some(42).into_iter()) +} +"#, + r#" +fn foo() -> impl Iterator { + Some(42).into_iter() +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs similarity index 51% rename from src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs rename to src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs index 8f0e9b4fe09d5..e6e1857a3f767 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -13,6 +13,22 @@ use syntax::{ use crate::{AssistContext, AssistId, AssistKind, Assists}; +// Assist: wrap_return_type_in_option +// +// Wrap the function's return type into Option. +// +// ``` +// # //- minicore: option +// fn foo() -> i32$0 { 42i32 } +// ``` +// -> +// ``` +// fn foo() -> Option { Some(42i32) } +// ``` +pub(crate) fn wrap_return_type_in_option(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + wrap_return_type(acc, ctx, WrapperKind::Option) +} + // Assist: wrap_return_type_in_result // // Wrap the function's return type into Result. @@ -26,6 +42,61 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // fn foo() -> Result { Ok(42i32) } // ``` pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + wrap_return_type(acc, ctx, WrapperKind::Result) +} + +enum WrapperKind { + Option, + Result, +} + +impl WrapperKind { + fn assist_id(&self) -> AssistId { + let s = match self { + WrapperKind::Option => "wrap_return_type_in_option", + WrapperKind::Result => "wrap_return_type_in_result", + }; + + AssistId(s, AssistKind::RefactorRewrite) + } + + fn label(&self) -> &'static str { + match self { + WrapperKind::Option => "Wrap return type in Option", + WrapperKind::Result => "Wrap return type in Result", + } + } + + fn happy_ident(&self) -> &'static str { + match self { + WrapperKind::Option => "Some", + WrapperKind::Result => "Ok", + } + } + + fn core_type(&self, famous_defs: FamousDefs<'_, '_>) -> Option { + match self { + WrapperKind::Option => famous_defs.core_option_Option(), + WrapperKind::Result => famous_defs.core_result_Result(), + } + } + + fn symbol(&self) -> hir::Symbol { + match self { + WrapperKind::Option => hir::sym::Option.clone(), + WrapperKind::Result => hir::sym::Result.clone(), + } + } + + fn wrap_type(&self, type_ref: &ast::Type) -> ast::Type { + match self { + WrapperKind::Option => make::ext::ty_option(type_ref.clone()), + WrapperKind::Result => make::ext::ty_result(type_ref.clone(), make::ty_placeholder()), + } + } +} + +fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>, kind: WrapperKind) -> Option<()> { let ret_type = ctx.find_node_at_offset::()?; let parent = ret_type.syntax().parent()?; let body = match_ast! { @@ -41,50 +112,49 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext< }; let type_ref = &ret_type.ty()?; - let core_result = - FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?; + let core_wrapper = + kind.core_type(FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()))?; let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); - if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_result) { - // The return type is already wrapped in a Result - cov_mark::hit!(wrap_return_type_in_result_simple_return_type_already_result); + if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) { + // The return type is already wrapped + cov_mark::hit!(wrap_return_type_simple_return_type_already_wrapped); return None; } - acc.add( - AssistId("wrap_return_type_in_result", AssistKind::RefactorRewrite), - "Wrap return type in Result", - type_ref.syntax().text_range(), - |edit| { - let new_result_ty = result_type(ctx, &core_result, type_ref).clone_for_update(); - let body = edit.make_mut(ast::Expr::BlockExpr(body)); - - let mut exprs_to_wrap = Vec::new(); - let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } + acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |edit| { + let alias = wrapper_alias(ctx, &core_wrapper, type_ref, kind.symbol()); + let new_return_ty = alias.unwrap_or_else(|| kind.wrap_type(type_ref)).clone_for_update(); + + let body = edit.make_mut(ast::Expr::BlockExpr(body)); + + let mut exprs_to_wrap = Vec::new(); + let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); + walk_expr(&body, &mut |expr| { + if let Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); } - }); - for_each_tail_expr(&body, tail_cb); - - for ret_expr_arg in exprs_to_wrap { - let ok_wrapped = make::expr_call( - make::expr_path(make::ext::ident_path("Ok")), - make::arg_list(iter::once(ret_expr_arg.clone())), - ) - .clone_for_update(); - ted::replace(ret_expr_arg.syntax(), ok_wrapped.syntax()); } + }); + for_each_tail_expr(&body, tail_cb); + + for ret_expr_arg in exprs_to_wrap { + let happy_wrapped = make::expr_call( + make::expr_path(make::ext::ident_path(kind.happy_ident())), + make::arg_list(iter::once(ret_expr_arg.clone())), + ) + .clone_for_update(); + ted::replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); + } - let old_result_ty = edit.make_mut(type_ref.clone()); - ted::replace(old_result_ty.syntax(), new_result_ty.syntax()); + let old_return_ty = edit.make_mut(type_ref.clone()); + ted::replace(old_return_ty.syntax(), new_return_ty.syntax()); + if let WrapperKind::Result = kind { // Add a placeholder snippet at the first generic argument that doesn't equal the return type. // This is normally the error type, but that may not be the case when we inserted a type alias. - let args = new_result_ty.syntax().descendants().find_map(ast::GenericArgList::cast); + let args = new_return_ty.syntax().descendants().find_map(ast::GenericArgList::cast); let error_type_arg = args.and_then(|list| { list.generic_args().find(|arg| match arg { ast::GenericArg::TypeArg(_) => arg.syntax().text() != type_ref.syntax().text(), @@ -97,25 +167,27 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext< edit.add_placeholder_snippet(cap, error_type_arg); } } - }, - ) + } + }) } -fn result_type( +// Try to find an wrapper type alias in the current scope (shadowing the default). +fn wrapper_alias( ctx: &AssistContext<'_>, - core_result: &hir::Enum, + core_wrapper: &hir::Enum, ret_type: &ast::Type, -) -> ast::Type { - // Try to find a Result type alias in the current scope (shadowing the default). - let result_path = hir::ModPath::from_segments( + wrapper: hir::Symbol, +) -> Option { + let wrapper_path = hir::ModPath::from_segments( hir::PathKind::Plain, - iter::once(hir::Name::new_symbol_root(hir::sym::Result.clone())), + iter::once(hir::Name::new_symbol_root(wrapper)), ); - let alias = ctx.sema.resolve_mod_path(ret_type.syntax(), &result_path).and_then(|def| { + + ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| { def.filter_map(|def| match def.as_module_def()? { hir::ModuleDef::TypeAlias(alias) => { let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?; - (&enum_ty == core_result).then_some(alias) + (&enum_ty == core_wrapper).then_some(alias) } _ => None, }) @@ -141,9 +213,7 @@ fn result_type( let name = name.as_str(); Some(make::ty(&format!("{name}<{generic_params}>"))) }) - }); - // If there is no applicable alias in scope use the default Result type. - alias.unwrap_or_else(|| make::ext::ty_result(ret_type.clone(), make::ty_placeholder())) + }) } fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { @@ -166,6 +236,1027 @@ mod tests { use super::*; + #[test] + fn wrap_return_type_in_option_simple() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i3$02 { + let test = "test"; + return 42i32; +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_break_split_tail() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i3$02 { + loop { + break if true { + 1 + } else { + 0 + }; + } +} +"#, + r#" +fn foo() -> Option { + loop { + break if true { + Some(1) + } else { + Some(0) + }; + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> i32$0 { + let test = "test"; + return 42i32; + }; +} +"#, + r#" +fn foo() { + || -> Option { + let test = "test"; + return Some(42i32); + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_bad_cursor() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32 { + let test = "test";$0 + return 42i32; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_bad_cursor_closure() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> i32 { + let test = "test";$0 + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_closure_non_block() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { || -> i$032 3; } +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_already_option_std() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> core::option::Option { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_already_option() { + cov_mark::check!(wrap_return_type_simple_return_type_already_wrapped); + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> Option { + let test = "test"; + return 42i32; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_return_type_already_option_closure() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> Option { + let test = "test"; + return 42i32; + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_cursor() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> $0i32 { + let test = "test"; + return 42i32; +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() ->$0 i32 { + let test = "test"; + 42i32 +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + Some(42i32) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || ->$0 i32 { + let test = "test"; + 42i32 + }; +} +"#, + r#" +fn foo() { + || -> Option { + let test = "test"; + Some(42i32) + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_only() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { 42i32 } +"#, + r#" +fn foo() -> Option { Some(42i32) } +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + if true { + 42i32 + } else { + 24i32 + } +} +"#, + r#" +fn foo() -> Option { + if true { + Some(42i32) + } else { + Some(24i32) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_without_block_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() { + || -> i32$0 { + if true { + 42i32 + } else { + 24i32 + } + }; +} +"#, + r#" +fn foo() { + || -> Option { + if true { + Some(42i32) + } else { + Some(24i32) + } + }; +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_nested_if() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + if true { + if false { + 1 + } else { + 2 + } + } else { + 24i32 + } +} +"#, + r#" +fn foo() -> Option { + if true { + if false { + Some(1) + } else { + Some(2) + } + } else { + Some(24i32) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_await() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +async fn foo() -> i$032 { + if true { + if false { + 1.await + } else { + 2.await + } + } else { + 24i32.await + } +} +"#, + r#" +async fn foo() -> Option { + if true { + if false { + Some(1.await) + } else { + Some(2.await) + } + } else { + Some(24i32.await) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_array() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> [i32;$0 3] { [1, 2, 3] } +"#, + r#" +fn foo() -> Option<[i32; 3]> { Some([1, 2, 3]) } +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_cast() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -$0> i32 { + if true { + if false { + 1 as i32 + } else { + 2 as i32 + } + } else { + 24 as i32 + } +} +"#, + r#" +fn foo() -> Option { + if true { + if false { + Some(1 as i32) + } else { + Some(2 as i32) + } + } else { + Some(24 as i32) + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_match() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + match my_var { + 5 => 42i32, + _ => 24i32, + } +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => Some(42i32), + _ => Some(24i32), + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_loop_with_tail() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + loop { + println!("test"); + 5 + } + my_var +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + loop { + println!("test"); + 5 + } + Some(my_var) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_loop_in_let_stmt() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = let x = loop { + break 1; + }; + my_var +} +"#, + r#" +fn foo() -> Option { + let my_var = let x = loop { + break 1; + }; + Some(my_var) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_match_return_expr() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return 24i32, + }; + res +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + let res = match my_var { + 5 => 42i32, + _ => return Some(24i32), + }; + Some(res) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return 24i32; + }; + res +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + let res = if my_var == 5 { + 42i32 + } else { + return Some(24i32); + }; + Some(res) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_match_deeper() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let my_var = 5; + match my_var { + 5 => { + if true { + 42i32 + } else { + 25i32 + } + }, + _ => { + let test = "test"; + if test == "test" { + return bar(); + } + 53i32 + }, + } +} +"#, + r#" +fn foo() -> Option { + let my_var = 5; + match my_var { + 5 => { + if true { + Some(42i32) + } else { + Some(25i32) + } + }, + _ => { + let test = "test"; + if test == "test" { + return Some(bar()); + } + Some(53i32) + }, + } +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_tail_block_like_early_return() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i$032 { + let test = "test"; + if test == "test" { + return 24i32; + } + 53i32 +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + Some(53i32) +} +"#, + ); + } + + #[test] + fn wrap_return_in_option_tail_position() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(num: i32) -> $0i32 { + return num +} +"#, + r#" +fn foo(num: i32) -> Option { + return Some(num) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_closure() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) ->$0 u32 { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + let true_closure = || { return true; }; + if the_field < 5 { + let mut i = 0; + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u32$0 { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return 99; + } else { + return 0; + } + } + let t = None; + + t.unwrap_or_else(|| the_field) +} +"#, + r#" +fn foo(the_field: u32) -> Option { + let true_closure = || { + return true; + }; + if the_field < 5 { + let mut i = 0; + + + if true_closure() { + return Some(99); + } else { + return Some(0); + } + } + let t = None; + + Some(t.unwrap_or_else(|| the_field)) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_option_simple_with_weird_forms() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i32$0 { + let test = "test"; + if test == "test" { + return 24i32; + } + let mut i = 0; + loop { + if i == 1 { + break 55; + } + i += 1; + } +} +"#, + r#" +fn foo() -> Option { + let test = "test"; + if test == "test" { + return Some(24i32); + } + let mut i = 0; + loop { + if i == 1 { + break Some(55); + } + i += 1; + } +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u32$0 { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return 55u32; + } + i += 3; + } + match i { + 5 => return 99, + _ => return 0, + }; + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + loop { + if i > 5 { + return Some(55u32); + } + i += 3; + } + match i { + 5 => return Some(99), + _ => return Some(0), + }; + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u3$02 { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return 99, + _ => return 0, + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + match i { + 5 => return Some(99), + _ => return Some(0), + } + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> u32$0 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99 + } else { + return 0 + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99) + } else { + return Some(0) + } + } + Some(the_field) +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo(the_field: u32) -> $0u32 { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return 99; + } else { + return 0; + } + } + the_field +} +"#, + r#" +fn foo(the_field: u32) -> Option { + if the_field < 5 { + let mut i = 0; + if i == 5 { + return Some(99); + } else { + return Some(0); + } + } + Some(the_field) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_option_type() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +type Option = core::option::Option; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +type Option = core::option::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +type Option2 = core::option::Option; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +type Option2 = core::option::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_imported_local_option_type() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::Option; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::*; + +fn foo() -> i3$02 { + return 42i32; +} +"#, + r#" +mod some_module { + pub type Option = core::option::Option; +} + +use some_module::*; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_option_type_from_function_body() { + check_assist( + wrap_return_type_in_option, + r#" +//- minicore: option +fn foo() -> i3$02 { + type Option = core::option::Option; + 0 +} +"#, + r#" +fn foo() -> Option { + type Option = core::option::Option; + Some(0) +} +"#, + ); + } + + #[test] + fn wrap_return_type_in_local_option_type_already_using_alias() { + check_assist_not_applicable( + wrap_return_type_in_option, + r#" +//- minicore: option +pub type Option = core::option::Option; + +fn foo() -> Option { + return Some(42i32); +} +"#, + ); + } + #[test] fn wrap_return_type_in_result_simple() { check_assist( @@ -187,7 +1278,7 @@ fn foo() -> Result { } #[test] - fn wrap_return_type_break_split_tail() { + fn wrap_return_type_in_result_break_split_tail() { check_assist( wrap_return_type_in_result, r#" @@ -297,7 +1388,7 @@ fn foo() -> core::result::Result { #[test] fn wrap_return_type_in_result_simple_return_type_already_result() { - cov_mark::check!(wrap_return_type_in_result_simple_return_type_already_result); + cov_mark::check!(wrap_return_type_simple_return_type_already_wrapped); check_assist_not_applicable( wrap_return_type_in_result, r#" @@ -786,7 +1877,7 @@ fn foo() -> Result { } #[test] - fn wrap_return_in_tail_position() { + fn wrap_return_in_result_tail_position() { check_assist( wrap_return_type_in_result, r#" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs deleted file mode 100644 index 90cfc2ef17c74..0000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type_in_option.rs +++ /dev/null @@ -1,1173 +0,0 @@ -use std::iter; - -use hir::HasSource; -use ide_db::{ - famous_defs::FamousDefs, - syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, -}; -use itertools::Itertools; -use syntax::{ - ast::{self, make, Expr, HasGenericParams}, - match_ast, ted, AstNode, ToSmolStr, -}; - -use crate::{AssistContext, AssistId, AssistKind, Assists}; - -// Assist: wrap_return_type_in_option -// -// Wrap the function's return type into Option. -// -// ``` -// # //- minicore: option -// fn foo() -> i32$0 { 42i32 } -// ``` -// -> -// ``` -// fn foo() -> Option { Some(42i32) } -// ``` -pub(crate) fn wrap_return_type_in_option(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let ret_type = ctx.find_node_at_offset::()?; - let parent = ret_type.syntax().parent()?; - let body = match_ast! { - match parent { - ast::Fn(func) => func.body()?, - ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, - // closures require a block when a return type is specified - _ => return None, - }, - _ => return None, - } - }; - - let type_ref = &ret_type.ty()?; - let core_option = - FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_option_Option()?; - - let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); - if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_option) { - // The return type is already wrapped in an Option - cov_mark::hit!(wrap_return_type_in_option_simple_return_type_already_option); - return None; - } - - acc.add( - AssistId("wrap_return_type_in_option", AssistKind::RefactorRewrite), - "Wrap return type in Option", - type_ref.syntax().text_range(), - |edit| { - let new_option_ty = option_type(ctx, &core_option, type_ref).clone_for_update(); - let body = edit.make_mut(ast::Expr::BlockExpr(body)); - - let mut exprs_to_wrap = Vec::new(); - let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } - } - }); - for_each_tail_expr(&body, tail_cb); - - for ret_expr_arg in exprs_to_wrap { - let some_wrapped = make::expr_call( - make::expr_path(make::ext::ident_path("Some")), - make::arg_list(iter::once(ret_expr_arg.clone())), - ) - .clone_for_update(); - ted::replace(ret_expr_arg.syntax(), some_wrapped.syntax()); - } - - let old_option_ty = edit.make_mut(type_ref.clone()); - ted::replace(old_option_ty.syntax(), new_option_ty.syntax()); - }, - ) -} - -fn option_type( - ctx: &AssistContext<'_>, - core_option: &hir::Enum, - ret_type: &ast::Type, -) -> ast::Type { - // Try to find an Option type alias in the current scope (shadowing the default). - let option_path = hir::ModPath::from_segments( - hir::PathKind::Plain, - iter::once(hir::Name::new_symbol_root(hir::sym::Option.clone())), - ); - let alias = ctx.sema.resolve_mod_path(ret_type.syntax(), &option_path).and_then(|def| { - def.filter_map(|def| match def.as_module_def()? { - hir::ModuleDef::TypeAlias(alias) => { - let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?; - (&enum_ty == core_option).then_some(alias) - } - _ => None, - }) - .find_map(|alias| { - let mut inserted_ret_type = false; - let generic_params = alias - .source(ctx.db())? - .value - .generic_param_list()? - .generic_params() - .map(|param| match param { - // Replace the very first type parameter with the functions return type. - ast::GenericParam::TypeParam(_) if !inserted_ret_type => { - inserted_ret_type = true; - ret_type.to_smolstr() - } - ast::GenericParam::LifetimeParam(_) => make::lifetime("'_").to_smolstr(), - _ => make::ty_placeholder().to_smolstr(), - }) - .join(", "); - - let name = alias.name(ctx.db()); - let name = name.as_str(); - Some(make::ty(&format!("{name}<{generic_params}>"))) - }) - }); - // If there is no applicable alias in scope use the default Option type. - alias.unwrap_or_else(|| make::ext::ty_option(ret_type.clone())) -} - -fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { - match e { - Expr::BreakExpr(break_expr) => { - if let Some(break_expr_arg) = break_expr.expr() { - for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) - } - } - Expr::ReturnExpr(_) => { - // all return expressions have already been handled by the walk loop - } - e => acc.push(e.clone()), - } -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; - - use super::*; - - #[test] - fn wrap_return_type_in_option_simple() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i3$02 { - let test = "test"; - return 42i32; -} -"#, - r#" -fn foo() -> Option { - let test = "test"; - return Some(42i32); -} -"#, - ); - } - - #[test] - fn wrap_return_type_break_split_tail() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i3$02 { - loop { - break if true { - 1 - } else { - 0 - }; - } -} -"#, - r#" -fn foo() -> Option { - loop { - break if true { - Some(1) - } else { - Some(0) - }; - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_closure() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() { - || -> i32$0 { - let test = "test"; - return 42i32; - }; -} -"#, - r#" -fn foo() { - || -> Option { - let test = "test"; - return Some(42i32); - }; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_return_type_bad_cursor() { - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32 { - let test = "test";$0 - return 42i32; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() { - || -> i32 { - let test = "test";$0 - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_closure_non_block() { - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() { || -> i$032 3; } -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_return_type_already_option_std() { - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> core::option::Option { - let test = "test"; - return 42i32; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_return_type_already_option() { - cov_mark::check!(wrap_return_type_in_option_simple_return_type_already_option); - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> Option { - let test = "test"; - return 42i32; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_return_type_already_option_closure() { - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() { - || -> Option { - let test = "test"; - return 42i32; - }; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_cursor() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> $0i32 { - let test = "test"; - return 42i32; -} -"#, - r#" -fn foo() -> Option { - let test = "test"; - return Some(42i32); -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() ->$0 i32 { - let test = "test"; - 42i32 -} -"#, - r#" -fn foo() -> Option { - let test = "test"; - Some(42i32) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_closure() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() { - || ->$0 i32 { - let test = "test"; - 42i32 - }; -} -"#, - r#" -fn foo() { - || -> Option { - let test = "test"; - Some(42i32) - }; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_only() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { 42i32 } -"#, - r#" -fn foo() -> Option { Some(42i32) } -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_block_like() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - if true { - 42i32 - } else { - 24i32 - } -} -"#, - r#" -fn foo() -> Option { - if true { - Some(42i32) - } else { - Some(24i32) - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_without_block_closure() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() { - || -> i32$0 { - if true { - 42i32 - } else { - 24i32 - } - }; -} -"#, - r#" -fn foo() { - || -> Option { - if true { - Some(42i32) - } else { - Some(24i32) - } - }; -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_nested_if() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - if true { - if false { - 1 - } else { - 2 - } - } else { - 24i32 - } -} -"#, - r#" -fn foo() -> Option { - if true { - if false { - Some(1) - } else { - Some(2) - } - } else { - Some(24i32) - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_await() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -async fn foo() -> i$032 { - if true { - if false { - 1.await - } else { - 2.await - } - } else { - 24i32.await - } -} -"#, - r#" -async fn foo() -> Option { - if true { - if false { - Some(1.await) - } else { - Some(2.await) - } - } else { - Some(24i32.await) - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_array() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> [i32;$0 3] { [1, 2, 3] } -"#, - r#" -fn foo() -> Option<[i32; 3]> { Some([1, 2, 3]) } -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_cast() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -$0> i32 { - if true { - if false { - 1 as i32 - } else { - 2 as i32 - } - } else { - 24 as i32 - } -} -"#, - r#" -fn foo() -> Option { - if true { - if false { - Some(1 as i32) - } else { - Some(2 as i32) - } - } else { - Some(24 as i32) - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_block_like_match() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let my_var = 5; - match my_var { - 5 => 42i32, - _ => 24i32, - } -} -"#, - r#" -fn foo() -> Option { - let my_var = 5; - match my_var { - 5 => Some(42i32), - _ => Some(24i32), - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_loop_with_tail() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let my_var = 5; - loop { - println!("test"); - 5 - } - my_var -} -"#, - r#" -fn foo() -> Option { - let my_var = 5; - loop { - println!("test"); - 5 - } - Some(my_var) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_loop_in_let_stmt() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let my_var = let x = loop { - break 1; - }; - my_var -} -"#, - r#" -fn foo() -> Option { - let my_var = let x = loop { - break 1; - }; - Some(my_var) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_block_like_match_return_expr() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let my_var = 5; - let res = match my_var { - 5 => 42i32, - _ => return 24i32, - }; - res -} -"#, - r#" -fn foo() -> Option { - let my_var = 5; - let res = match my_var { - 5 => 42i32, - _ => return Some(24i32), - }; - Some(res) -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let my_var = 5; - let res = if my_var == 5 { - 42i32 - } else { - return 24i32; - }; - res -} -"#, - r#" -fn foo() -> Option { - let my_var = 5; - let res = if my_var == 5 { - 42i32 - } else { - return Some(24i32); - }; - Some(res) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_block_like_match_deeper() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let my_var = 5; - match my_var { - 5 => { - if true { - 42i32 - } else { - 25i32 - } - }, - _ => { - let test = "test"; - if test == "test" { - return bar(); - } - 53i32 - }, - } -} -"#, - r#" -fn foo() -> Option { - let my_var = 5; - match my_var { - 5 => { - if true { - Some(42i32) - } else { - Some(25i32) - } - }, - _ => { - let test = "test"; - if test == "test" { - return Some(bar()); - } - Some(53i32) - }, - } -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_tail_block_like_early_return() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i$032 { - let test = "test"; - if test == "test" { - return 24i32; - } - 53i32 -} -"#, - r#" -fn foo() -> Option { - let test = "test"; - if test == "test" { - return Some(24i32); - } - Some(53i32) -} -"#, - ); - } - - #[test] - fn wrap_return_in_tail_position() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(num: i32) -> $0i32 { - return num -} -"#, - r#" -fn foo(num: i32) -> Option { - return Some(num) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_closure() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(the_field: u32) ->$0 u32 { - let true_closure = || { return true; }; - if the_field < 5 { - let mut i = 0; - if true_closure() { - return 99; - } else { - return 0; - } - } - the_field -} -"#, - r#" -fn foo(the_field: u32) -> Option { - let true_closure = || { return true; }; - if the_field < 5 { - let mut i = 0; - if true_closure() { - return Some(99); - } else { - return Some(0); - } - } - Some(the_field) -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(the_field: u32) -> u32$0 { - let true_closure = || { - return true; - }; - if the_field < 5 { - let mut i = 0; - - - if true_closure() { - return 99; - } else { - return 0; - } - } - let t = None; - - t.unwrap_or_else(|| the_field) -} -"#, - r#" -fn foo(the_field: u32) -> Option { - let true_closure = || { - return true; - }; - if the_field < 5 { - let mut i = 0; - - - if true_closure() { - return Some(99); - } else { - return Some(0); - } - } - let t = None; - - Some(t.unwrap_or_else(|| the_field)) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_option_simple_with_weird_forms() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i32$0 { - let test = "test"; - if test == "test" { - return 24i32; - } - let mut i = 0; - loop { - if i == 1 { - break 55; - } - i += 1; - } -} -"#, - r#" -fn foo() -> Option { - let test = "test"; - if test == "test" { - return Some(24i32); - } - let mut i = 0; - loop { - if i == 1 { - break Some(55); - } - i += 1; - } -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(the_field: u32) -> u32$0 { - if the_field < 5 { - let mut i = 0; - loop { - if i > 5 { - return 55u32; - } - i += 3; - } - match i { - 5 => return 99, - _ => return 0, - }; - } - the_field -} -"#, - r#" -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - loop { - if i > 5 { - return Some(55u32); - } - i += 3; - } - match i { - 5 => return Some(99), - _ => return Some(0), - }; - } - Some(the_field) -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(the_field: u32) -> u3$02 { - if the_field < 5 { - let mut i = 0; - match i { - 5 => return 99, - _ => return 0, - } - } - the_field -} -"#, - r#" -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - match i { - 5 => return Some(99), - _ => return Some(0), - } - } - Some(the_field) -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(the_field: u32) -> u32$0 { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return 99 - } else { - return 0 - } - } - the_field -} -"#, - r#" -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return Some(99) - } else { - return Some(0) - } - } - Some(the_field) -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo(the_field: u32) -> $0u32 { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return 99; - } else { - return 0; - } - } - the_field -} -"#, - r#" -fn foo(the_field: u32) -> Option { - if the_field < 5 { - let mut i = 0; - if i == 5 { - return Some(99); - } else { - return Some(0); - } - } - Some(the_field) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_local_option_type() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -type Option = core::option::Option; - -fn foo() -> i3$02 { - return 42i32; -} -"#, - r#" -type Option = core::option::Option; - -fn foo() -> Option { - return Some(42i32); -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -type Option2 = core::option::Option; - -fn foo() -> i3$02 { - return 42i32; -} -"#, - r#" -type Option2 = core::option::Option; - -fn foo() -> Option { - return Some(42i32); -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_imported_local_option_type() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -mod some_module { - pub type Option = core::option::Option; -} - -use some_module::Option; - -fn foo() -> i3$02 { - return 42i32; -} -"#, - r#" -mod some_module { - pub type Option = core::option::Option; -} - -use some_module::Option; - -fn foo() -> Option { - return Some(42i32); -} -"#, - ); - - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -mod some_module { - pub type Option = core::option::Option; -} - -use some_module::*; - -fn foo() -> i3$02 { - return 42i32; -} -"#, - r#" -mod some_module { - pub type Option = core::option::Option; -} - -use some_module::*; - -fn foo() -> Option { - return Some(42i32); -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_local_option_type_from_function_body() { - check_assist( - wrap_return_type_in_option, - r#" -//- minicore: option -fn foo() -> i3$02 { - type Option = core::option::Option; - 0 -} -"#, - r#" -fn foo() -> Option { - type Option = core::option::Option; - Some(0) -} -"#, - ); - } - - #[test] - fn wrap_return_type_in_local_option_type_already_using_alias() { - check_assist_not_applicable( - wrap_return_type_in_option, - r#" -//- minicore: option -pub type Option = core::option::Option; - -fn foo() -> Option { - return Some(42i32); -} -"#, - ); - } -} 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 63a3fec3f41d5..8114888d6c3fa 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -223,11 +223,9 @@ mod handlers { mod unnecessary_async; mod unqualify_method_call; mod unwrap_block; - mod unwrap_option_return_type; - mod unwrap_result_return_type; + mod unwrap_return_type; mod unwrap_tuple; - mod wrap_return_type_in_option; - mod wrap_return_type_in_result; + mod wrap_return_type; mod wrap_unwrap_cfg_attr; pub(crate) fn all() -> &'static [Handler] { @@ -357,12 +355,12 @@ mod handlers { unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, unwrap_block::unwrap_block, - unwrap_option_return_type::unwrap_option_return_type, - unwrap_result_return_type::unwrap_result_return_type, + unwrap_return_type::unwrap_option_return_type, + unwrap_return_type::unwrap_result_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, - wrap_return_type_in_option::wrap_return_type_in_option, - wrap_return_type_in_result::wrap_return_type_in_result, + wrap_return_type::wrap_return_type_in_option, + wrap_return_type::wrap_return_type_in_result, wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr, // These are manually sorted for better priorities. By default, From 325d48fe7a9fe70c533f7bbc9553afd0cc0a465e Mon Sep 17 00:00:00 2001 From: David Barsky Date: Thu, 17 Oct 2024 11:53:19 -0400 Subject: [PATCH 04/32] internal: fix lldb-dap unconditionally calling rustc --- .../rust-analyzer/editors/code/src/debug.ts | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 77ab44f24ceb7..9e2e3d2185bf4 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -6,7 +6,6 @@ import type * as ra from "./lsp_ext"; import { Cargo } from "./toolchain"; import type { Ctx } from "./ctx"; import { createTaskFromRunnable, prepareEnv } from "./run"; -import { execSync } from "node:child_process"; import { execute, isCargoRunnableArgs, unwrapUndefinable } from "./util"; import type { Config } from "./config"; @@ -152,9 +151,24 @@ async function getDebugConfiguration( const env = prepareEnv(inheritEnv, runnable.label, runnableArgs, config.runnablesExtraEnv); const executable = await getDebugExecutable(runnableArgs, env); let sourceFileMap = debugOptions.sourceFileMap; + if (sourceFileMap === "auto") { sourceFileMap = {}; - await discoverSourceFileMap(sourceFileMap, env, wsFolder); + const computedSourceFileMap = await discoverSourceFileMap(env, wsFolder); + + if (computedSourceFileMap) { + // lldb-dap requires passing the source map as an array of two element arrays. + // the two element array contains a source and destination pathname. + // TODO: remove lldb-dap-specific post-processing once + // https://github.com/llvm/llvm-project/pull/106919/ is released in the extension. + if (provider.type === "lldb-dap") { + provider.additional["sourceMap"] = [ + [computedSourceFileMap?.source, computedSourceFileMap?.destination], + ]; + } else { + sourceFileMap[computedSourceFileMap.source] = computedSourceFileMap.destination; + } + } } const debugConfig = getDebugConfig( @@ -189,11 +203,15 @@ async function getDebugConfiguration( return debugConfig; } +type SourceFileMap = { + source: string; + destination: string; +}; + async function discoverSourceFileMap( - sourceFileMap: Record, env: Record, cwd: string, -) { +): Promise { const sysroot = env["RUSTC_TOOLCHAIN"]; if (sysroot) { // let's try to use the default toolchain @@ -203,9 +221,11 @@ async function discoverSourceFileMap( const commitHash = rx.exec(data)?.[1]; if (commitHash) { const rustlib = path.normalize(sysroot + "/lib/rustlib/src/rust"); - sourceFileMap[`/rustc/${commitHash}/`] = rustlib; + return { source: rustlib, destination: rustlib }; } } + + return; } type PropertyFetcher = ( @@ -218,7 +238,7 @@ type DebugConfigProvider; sourceFileMapProperty?: keyof DebugConfig; type: Type; - additional?: Record; + additional: Record; }; type KnownEnginesType = (typeof knownEngines)[keyof typeof knownEngines]; @@ -236,16 +256,7 @@ const knownEngines: { "args", runnableArgs.executableArgs, ], - additional: { - sourceMap: [ - [ - `/rustc/${/commit-hash:\s(.*)$/m.exec( - execSync("rustc -V -v", {}).toString(), - )?.[1]}/library`, - "${config:rust-analyzer.cargo.sysroot}/lib/rustlib/src/rust/library", - ], - ], - }, + additional: {}, }, "vadimcn.vscode-lldb": { type: "lldb", From 8df5f37e1c48f950278f1213c475265caa5a0770 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Oct 2024 10:56:23 +0200 Subject: [PATCH 05/32] fix: Fix CI running analysis-stats incorrectly against the standard libraries --- src/tools/rust-analyzer/.github/workflows/ci.yaml | 6 +++--- .../rust-analyzer/crates/project-model/src/tests.rs | 3 --- .../crates/rust-analyzer/src/cli/analysis_stats.rs | 9 +++++++-- .../rust-analyzer/crates/rust-analyzer/src/cli/flags.rs | 3 +++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 6d3e488bb0821..5cf4a8fd43939 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -104,11 +104,11 @@ jobs: if: matrix.os == 'ubuntu-latest' run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats . - - name: Run analysis-stats on rust std library + - name: Run analysis-stats on the rust standard libraries if: matrix.os == 'ubuntu-latest' env: - RUSTC_BOOTSTRAP: 1 - run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std + RUSTC_BOOTSTRAP: 1 + run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/ - name: clippy if: matrix.os == 'windows-latest' diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 5099697a6963c..ef115494a8886 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -222,8 +222,6 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() { } #[test] -// FIXME Remove the ignore -#[ignore = "requires nightly until the sysroot ships a cargo workspace for library on stable"] fn smoke_test_real_sysroot_cargo() { let file_map = &mut FxHashMap::::default(); let meta: Metadata = get_test_json_file("hello-world-metadata.json"); @@ -235,7 +233,6 @@ fn smoke_test_real_sysroot_cargo() { &Default::default(), ); assert!(matches!(sysroot.mode(), SysrootMode::Workspace(_))); - let project_workspace = ProjectWorkspace { kind: ProjectWorkspaceKind::Cargo { cargo: cargo_workspace, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index c2164614274c4..51c81a0d1a640 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -6,6 +6,7 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; +use cfg::{CfgAtom, CfgDiff}; use hir::{ db::{DefDatabase, ExpandDatabase, HirDatabase}, Adt, AssocItem, Crate, DefWithBody, HasSource, HirDisplay, HirFileIdExt, ImportPathConfig, @@ -31,7 +32,7 @@ use itertools::Itertools; use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use oorandom::Rand32; use profile::{Bytes, StopWatch}; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; +use project_model::{CargoConfig, CfgOverrides, ProjectManifest, ProjectWorkspace, RustLibSource}; use rayon::prelude::*; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{AstNode, SyntaxNode}; @@ -65,7 +66,11 @@ impl flags::AnalysisStats { false => Some(RustLibSource::Discover), }, all_targets: true, - set_test: true, + set_test: !self.no_test, + cfg_overrides: CfgOverrides { + global: CfgDiff::new(vec![CfgAtom::Flag(hir::sym::miri.clone())], vec![]).unwrap(), + selective: Default::default(), + }, ..Default::default() }; let no_progress = &|_| (); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs index 60d621b214ade..ff24602144a9d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/flags.rs @@ -71,6 +71,8 @@ xflags::xflags! { optional --with-deps /// Don't load sysroot crates (`std`, `core` & friends). optional --no-sysroot + /// Don't set #[cfg(test)]. + optional --no-test /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis. optional --disable-build-scripts @@ -233,6 +235,7 @@ pub struct AnalysisStats { pub only: Option, pub with_deps: bool, pub no_sysroot: bool, + pub no_test: bool, pub disable_build_scripts: bool, pub disable_proc_macros: bool, pub proc_macro_srv: Option, From c9f2a0e94bb2bdd5b4dadb6d8de842bd8309670d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Oct 2024 12:41:14 +0200 Subject: [PATCH 06/32] internal: Add more trivially `Sized` types to `is_sized` check --- .../rust-analyzer/crates/hir-ty/src/infer/unify.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 7300453ff0014..e4881d7520138 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -917,9 +917,19 @@ impl<'a> InferenceTable<'a> { /// Check if given type is `Sized` or not pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { // Early return for some obvious types - if matches!(ty.kind(Interner), TyKind::Scalar(..) | TyKind::Ref(..) | TyKind::Raw(..)) { + if matches!( + ty.kind(Interner), + TyKind::Scalar(..) + | TyKind::Ref(..) + | TyKind::Raw(..) + | TyKind::Never + | TyKind::FnDef(..) + | TyKind::Array(..) + | TyKind::Function(_) + ) { return true; } + if let Some((AdtId::StructId(id), subst)) = ty.as_adt() { let struct_data = self.db.struct_data(id); if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() { From db6824a447afdd162dd0791c641a360bb7f3b4d1 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Thu, 17 Oct 2024 11:53:19 -0400 Subject: [PATCH 07/32] internal: fix lldb-dap unconditionally calling rustc From f01ebd6d13f4686817365c4304cacbce8d1e6cf2 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Thu, 17 Oct 2024 13:55:30 -0400 Subject: [PATCH 08/32] vscode: update some dependencies --- src/tools/rust-analyzer/Cargo.lock | 10 +- .../editors/code/package-lock.json | 1525 +++++++++++++++-- .../rust-analyzer/editors/code/package.json | 4 +- 3 files changed, 1401 insertions(+), 138 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 4a6da47a47df7..a99294033b44d 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -731,7 +731,7 @@ dependencies = [ "indexmap", "itertools", "limit", - "line-index 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "line-index 0.1.1", "memchr", "nohash-hasher", "parser", @@ -940,19 +940,19 @@ version = "0.0.0" [[package]] name = "line-index" version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d61795376ae2683928c218fda7d7d7db136fd38c06b7552904667f0d55580a" dependencies = [ "nohash-hasher", - "oorandom", "text-size", ] [[package]] name = "line-index" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d61795376ae2683928c218fda7d7d7db136fd38c06b7552904667f0d55580a" +version = "0.1.2" dependencies = [ "nohash-hasher", + "oorandom", "text-size", ] diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 7de7576317771..10b633511d3e0 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -22,14 +22,14 @@ "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.8", - "@vscode/vsce": "^2.19.0", + "@vscode/vsce": "^3.0.0", "esbuild": "^0.18.12", "eslint": "^8.44.0", "eslint-config-prettier": "^8.8.0", "ovsx": "^0.8.2", "prettier": "^3.0.0", "tslib": "^2.6.0", - "typescript": "^5.1.6" + "typescript": "^5.6.0" }, "engines": { "vscode": "^1.78.0" @@ -44,6 +44,218 @@ "node": ">=0.10.0" } }, + "node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", + "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.17.0.tgz", + "integrity": "sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.9.0", + "@azure/logger": "^1.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", + "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", + "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.5.0.tgz", + "integrity": "sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.26.1", + "@azure/msal-node": "^2.15.0", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz", + "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "3.26.1", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.26.1.tgz", + "integrity": "sha512-y78sr9g61aCAH9fcLO1um+oHFXc1/5Ap88RIsUSuzkm0BHzFnN+PXGaQeuM1h5Qf5dTnWNOd6JqkskkMPAhh7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "14.15.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.15.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.15.0.tgz", + "integrity": "sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.15.0.tgz", + "integrity": "sha512-gVPW8YLz92ZeCibQH2QUw96odJoiM3k/ZPH3f2HxptozmH6+OnyyvKXo/Egg39HAM230akarQKHf0W74UHlh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "14.15.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.18.12", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.12.tgz", @@ -496,6 +708,109 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -778,26 +1093,31 @@ } }, "node_modules/@vscode/vsce": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", - "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.1.1.tgz", + "integrity": "sha512-N62Ca9ElRPLUUzf7l9CeEBlLrYzFPRQq7huKk4pVW+LjIOSXfFIPudixn5QvZcz+yXDOh15IopI3K2o3y9666Q==", "dev": true, + "license": "MIT", "dependencies": { - "azure-devops-node-api": "^11.0.1", + "@azure/identity": "^4.1.0", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", "chalk": "^2.4.2", "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", + "cockatiel": "^3.1.2", + "commander": "^6.2.1", + "form-data": "^4.0.0", + "glob": "^11.0.0", "hosted-git-info": "^4.0.2", "jsonc-parser": "^3.2.0", "leven": "^3.1.0", - "markdown-it": "^12.3.2", + "markdown-it": "^14.1.0", "mime": "^1.3.4", "minimatch": "^3.0.3", "parse-semver": "^1.1.1", "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", + "semver": "^7.5.2", + "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", "xml2js": "^0.5.0", @@ -808,12 +1128,157 @@ "vsce": "vsce" }, "engines": { - "node": ">= 14" + "node": ">= 20" }, "optionalDependencies": { "keytar": "^7.7.0" } }, + "node_modules/@vscode/vsce-sign": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.4.tgz", + "integrity": "sha512-0uL32egStKYfy60IqnynAChMTbL0oqpqk0Ew0YHiIb+fayuGZWADuIPHWUcY1GCnAA+VgchOPDMxnc2R3XGWEA==", + "dev": true, + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.2", + "@vscode/vsce-sign-alpine-x64": "2.0.2", + "@vscode/vsce-sign-darwin-arm64": "2.0.2", + "@vscode/vsce-sign-darwin-x64": "2.0.2", + "@vscode/vsce-sign-linux-arm": "2.0.2", + "@vscode/vsce-sign-linux-arm64": "2.0.2", + "@vscode/vsce-sign-linux-x64": "2.0.2", + "@vscode/vsce-sign-win32-arm64": "2.0.2", + "@vscode/vsce-sign-win32-x64": "2.0.2" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.2.tgz", + "integrity": "sha512-E80YvqhtZCLUv3YAf9+tIbbqoinWLCO/B3j03yQPbjT3ZIHCliKZlsy1peNc4XNZ5uIb87Jn0HWx/ZbPXviuAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.2.tgz", + "integrity": "sha512-n1WC15MSMvTaeJ5KjWCzo0nzjydwxLyoHiMJHu1Ov0VWTZiddasmOQHekA47tFRycnt4FsQrlkSCTdgHppn6bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz", + "integrity": "sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.2.tgz", + "integrity": "sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.2.tgz", + "integrity": "sha512-Fkb5jpbfhZKVw3xwR6t7WYfwKZktVGNXdg1m08uEx1anO0oUPUkoQRsNm4QniL3hmfw0ijg00YA6TrxCRkPVOQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.2.tgz", + "integrity": "sha512-Ybeu7cA6+/koxszsORXX0OJk9N0GgfHq70Wqi4vv2iJCZvBrOWwcIrxKjvFtwyDgdeQzgPheH5nhLVl5eQy7WA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.2.tgz", + "integrity": "sha512-NsPPFVtLaTlVJKOiTnO8Cl78LZNWy0Q8iAg+LlBiCDEgC12Gt4WXOSs2pmcIjDYzj2kY4NwdeN1mBTaujYZaPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.2.tgz", + "integrity": "sha512-wPs848ymZ3Ny+Y1Qlyi7mcT6VSigG89FWQnp2qRYCyMhdJxOpA4lDwxzlpL8fG6xC8GjQjGDkwbkWUcCobvksQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.2.tgz", + "integrity": "sha512-pAiRN6qSAhDM5SVOIxgx+2xnoVUePHbRNC7OD2aOR3WltTKxxF25OfpK8h8UQ7A0BuRkSgREbB59DBlFk4iAeg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@vscode/vsce/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -826,6 +1291,16 @@ "node": ">=4" } }, + "node_modules/@vscode/vsce/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/@vscode/vsce/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -873,6 +1348,46 @@ "node": ">=0.8.0" } }, + "node_modules/@vscode/vsce/node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/vsce/node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vscode/vsce/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -882,15 +1397,6 @@ "node": ">=4" } }, - "node_modules/@vscode/vsce/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/@vscode/vsce/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -903,19 +1409,6 @@ "node": ">=4" } }, - "node_modules/@vscode/vsce/node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -1007,11 +1500,19 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/azure-devops-node-api": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", - "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", "dev": true, + "license": "MIT", "dependencies": { "tunnel": "0.0.6", "typed-rest-client": "^1.8.4" @@ -1132,14 +1633,28 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1234,6 +1749,16 @@ "node": ">=12" } }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1250,6 +1775,19 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -1780,6 +2318,34 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/delaunator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", @@ -1788,6 +2354,16 @@ "robust-predicates": "^3.0.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", @@ -1877,6 +2453,23 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1904,6 +2497,29 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.18.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.12.tgz", @@ -2156,6 +2772,16 @@ "node": ">=0.10.0" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -2309,6 +2935,38 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -2323,10 +2981,14 @@ "dev": true }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -2337,14 +2999,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2424,6 +3092,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -2436,18 +3117,6 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2457,11 +3126,38 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -2469,6 +3165,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -2642,6 +3351,22 @@ "is-ci": "bin.js" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2689,6 +3414,19 @@ "node": ">=8" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2701,6 +3439,22 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2731,6 +3485,52 @@ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -2743,6 +3543,29 @@ "setimmediate": "^1.0.5" } }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keytar": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", @@ -2787,12 +3610,13 @@ } }, "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, + "license": "MIT", "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "node_modules/locate-path": { @@ -2810,12 +3634,61 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2828,35 +3701,29 @@ } }, "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", @@ -2868,12 +3735,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2892,6 +3760,29 @@ "node": ">=4" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -2927,6 +3818,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -2998,10 +3899,14 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3015,6 +3920,24 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -3053,6 +3976,93 @@ "node": ">= 14" } }, + "node_modules/ovsx/node_modules/@vscode/vsce": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.32.0.tgz", + "integrity": "sha512-3EFJfsgrSftIqt3EtdRcAygy/OJ3hstyI1cDmIgkU9CFZW5C+3djr6mfosndCUqcVYuyjmxOK1xmFp/Bq7+NIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.1.0", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "cockatiel": "^3.1.2", + "commander": "^6.2.1", + "form-data": "^4.0.0", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^7.5.2", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 16" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/ovsx/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ovsx/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ovsx/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ovsx/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, "node_modules/ovsx/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -3062,6 +4072,90 @@ "node": ">= 6" } }, + "node_modules/ovsx/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/ovsx/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ovsx/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ovsx/node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/ovsx/node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/ovsx/node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ovsx/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ovsx/node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true, + "license": "MIT" + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3092,6 +4186,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -3180,6 +4281,33 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", + "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3284,13 +4412,24 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3478,6 +4617,24 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -3506,19 +4663,37 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -3575,6 +4750,17 @@ "node": ">=8" } }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -3597,6 +4783,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3608,6 +4810,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3684,15 +4900,13 @@ "dev": true }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8.17.0" + "node": ">=14.14" } }, "node_modules/to-regex-range": { @@ -3720,16 +4934,18 @@ } }, "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", - "dev": true + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", + "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "dev": true, + "license": "0BSD" }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -3772,10 +4988,11 @@ } }, "node_modules/typed-rest-client": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", - "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", "dev": true, + "license": "MIT", "dependencies": { "qs": "^6.9.1", "tunnel": "0.0.6", @@ -3783,10 +5000,11 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3796,16 +5014,18 @@ } }, "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" }, "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true, + "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", @@ -3828,6 +5048,16 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", @@ -3913,12 +5143,45 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a52b3d1ec5cc2..6c7f402dc5f93 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -58,14 +58,14 @@ "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.8", - "@vscode/vsce": "^2.19.0", + "@vscode/vsce": "^3.0.0", "esbuild": "^0.18.12", "eslint": "^8.44.0", "eslint-config-prettier": "^8.8.0", "ovsx": "^0.8.2", "prettier": "^3.0.0", "tslib": "^2.6.0", - "typescript": "^5.1.6" + "typescript": "^5.6.0" }, "activationEvents": [ "workspaceContains:Cargo.toml", From 00318bacbac315c39e4902d13c0bf73ec3519220 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 5 Oct 2024 08:44:26 +0200 Subject: [PATCH 09/32] Clamp Position::character to line length LSP says about Position::character > If the character value is greater than the line length it defaults back to the line length. but from_proto::offset() doesn't implement this. A client might for example request code actions for a whole line by sending Position::character=99999. I don't think there is ever a reason (besides laziness) why the client can't specify the line length instead but I guess we should not crash but follow protocol. Technically it should be a warning, not an error but warning is not shown by default so keep it at error I guess. Fixes #18240 --- src/tools/rust-analyzer/Cargo.toml | 2 +- .../crates/rust-analyzer/src/lsp/from_proto.rs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 8c099f324b46a..17cefe941e57f 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -96,7 +96,7 @@ test-fixture = { path = "./crates/test-fixture" } test-utils = { path = "./crates/test-utils" } # In-tree crates that are published separately and follow semver. See lib/README.md -line-index = { version = "0.1.1" } +line-index = { version = "0.1.2" } la-arena = { version = "0.3.1" } lsp-server = { version = "0.7.6" } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs index 1f4544887f062..47e9961cf13fc 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs @@ -35,10 +35,18 @@ pub(crate) fn offset( .ok_or_else(|| format_err!("Invalid wide col offset"))? } }; - let text_size = line_index.index.offset(line_col).ok_or_else(|| { + let line_range = line_index.index.line(line_col.line).ok_or_else(|| { format_err!("Invalid offset {line_col:?} (line index length: {:?})", line_index.index.len()) })?; - Ok(text_size) + let col = TextSize::from(line_col.col); + let clamped_len = col.min(line_range.len()); + if clamped_len < col { + tracing::error!( + "Position {line_col:?} column exceeds line length {}, clamping it", + u32::from(line_range.len()), + ); + } + Ok(line_range.start() + clamped_len) } pub(crate) fn text_range( From 1a93651b8c59031dc110420ab1b2f1935308771b Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 19 Oct 2024 01:10:31 +0300 Subject: [PATCH 10/32] Fix editorconfig glob --- src/tools/rust-analyzer/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/.editorconfig b/src/tools/rust-analyzer/.editorconfig index e337066f7eaca..6bb743a6736e5 100644 --- a/src/tools/rust-analyzer/.editorconfig +++ b/src/tools/rust-analyzer/.editorconfig @@ -13,5 +13,5 @@ max_line_length = 100 [*.md] indent_size = 2 -[*.{yml, yaml}] +[*.{yml,yaml}] indent_size = 2 From 0590422812c4c02b4292ee5043583f189d7f3647 Mon Sep 17 00:00:00 2001 From: Wei Xu <1222863+xuwaters@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:36:24 -0700 Subject: [PATCH 11/32] Increase TOKEN_LIMIT for hir-expand --- src/tools/rust-analyzer/crates/hir-expand/src/db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index d412bf4eee526..0d19ae202ce05 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -35,7 +35,7 @@ type MacroArgResult = (Arc, SyntaxFixupUndoInfo, Span); /// an error will be emitted. /// /// Actual max for `analysis-stats .` at some point: 30672. -static TOKEN_LIMIT: Limit = Limit::new(1_048_576); +static TOKEN_LIMIT: Limit = Limit::new(2_097_152); #[derive(Debug, Clone, Eq, PartialEq)] pub enum TokenExpander { From a400d7fb76dd30d30367d0262b0ffb3b64a79cc6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 5 Oct 2024 18:18:47 +1000 Subject: [PATCH 12/32] coverage: Make counter creation handle nodes/edges more uniformly --- .../src/coverage/counters.rs | 102 +++++++++--------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 9408815675692..c78a4924ee68a 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -104,24 +104,18 @@ impl CoverageCounters { BcbCounter::Counter { id } } - /// Creates a new physical counter attached a BCB node. - /// The node must not already have a counter. + /// Creates a new physical counter for a BCB node. fn make_phys_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { - let counter = self.make_counter_inner(CounterIncrementSite::Node { bcb }); - debug!(?bcb, ?counter, "node gets a physical counter"); - self.set_bcb_counter(bcb, counter) + self.make_counter_inner(CounterIncrementSite::Node { bcb }) } - /// Creates a new physical counter attached to a BCB edge. - /// The edge must not already have a counter. + /// Creates a new physical counter for a BCB edge. fn make_phys_edge_counter( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> BcbCounter { - let counter = self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb }); - debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); - self.set_bcb_edge_counter(from_bcb, to_bcb, counter) + self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb }) } fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { @@ -330,11 +324,21 @@ impl<'a> MakeBcbCounters<'a> { return; } - // Determine the set of out-edges that don't yet have edge counters. + // When choosing which out-edge should be given a counter expression, ignore edges that + // already have counters, or could use the existing counter of their target node. + let out_edge_has_counter = |to_bcb| { + if self.coverage_counters.bcb_edge_counters.contains_key(&(from_bcb, to_bcb)) { + return true; + } + self.basic_coverage_blocks.sole_predecessor(to_bcb) == Some(from_bcb) + && self.coverage_counters.bcb_counters[to_bcb].is_some() + }; + + // Determine the set of out-edges that could benefit from being given an expression. let candidate_successors = self.basic_coverage_blocks.successors[from_bcb] .iter() .copied() - .filter(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb)) + .filter(|&to_bcb| !out_edge_has_counter(to_bcb)) .collect::>(); debug!(?candidate_successors); @@ -371,14 +375,7 @@ impl<'a> MakeBcbCounters<'a> { ); debug!("{expression_to_bcb:?} gets an expression: {expression:?}"); - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(expression_to_bcb) { - // This edge normally wouldn't get its own counter, so attach the expression - // to its target node instead, so that `edge_has_no_counter` can see it. - assert_eq!(sole_pred, from_bcb); - self.coverage_counters.set_bcb_counter(expression_to_bcb, expression); - } else { - self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); - } + self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); } #[instrument(level = "debug", skip(self))] @@ -389,6 +386,19 @@ impl<'a> MakeBcbCounters<'a> { return counter_kind; } + let counter = self.make_node_counter_inner(bcb); + self.coverage_counters.set_bcb_counter(bcb, counter) + } + + fn make_node_counter_inner(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { + // If the node's sole in-edge already has a counter, use that. + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(bcb) + && let Some(&edge_counter) = + self.coverage_counters.bcb_edge_counters.get(&(sole_pred, bcb)) + { + return edge_counter; + } + let predecessors = self.basic_coverage_blocks.predecessors[bcb].as_slice(); // Handle cases where we can't compute a node's count from its in-edges: @@ -398,7 +408,9 @@ impl<'a> MakeBcbCounters<'a> { // leading to infinite recursion. if predecessors.len() <= 1 || predecessors.contains(&bcb) { debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor"); - return self.coverage_counters.make_phys_node_counter(bcb); + let counter = self.coverage_counters.make_phys_node_counter(bcb); + debug!(?bcb, ?counter, "node gets a physical counter"); + return counter; } // A BCB with multiple incoming edges can compute its count by ensuring that counters @@ -414,7 +426,7 @@ impl<'a> MakeBcbCounters<'a> { .expect("there must be at least one in-edge"); debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}"); - self.coverage_counters.set_bcb_counter(bcb, sum_of_in_edges) + sum_of_in_edges } #[instrument(level = "debug", skip(self))] @@ -422,6 +434,23 @@ impl<'a> MakeBcbCounters<'a> { &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, + ) -> BcbCounter { + // If the edge already has a counter, return it. + if let Some(&counter_kind) = + self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) + { + debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}"); + return counter_kind; + } + + let counter = self.make_edge_counter_inner(from_bcb, to_bcb); + self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter) + } + + fn make_edge_counter_inner( + &mut self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, ) -> BcbCounter { // If the target node has exactly one in-edge (i.e. this one), then just // use the node's counter, since it will have the same value. @@ -439,16 +468,10 @@ impl<'a> MakeBcbCounters<'a> { return self.get_or_make_node_counter(from_bcb); } - // If the edge already has a counter, return it. - if let Some(&counter_kind) = - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) - { - debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind; - } - // Make a new counter to count this edge. - self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb) + let counter = self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb); + debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); + counter } /// Given a set of candidate out-edges (represented by their successor node), @@ -508,21 +531,4 @@ impl<'a> MakeBcbCounters<'a> { None } - - #[inline] - fn edge_has_no_counter( - &self, - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - ) -> bool { - let edge_counter = - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { - assert_eq!(sole_pred, from_bcb); - self.coverage_counters.bcb_counters[to_bcb] - } else { - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)).copied() - }; - - edge_counter.is_none() - } } From 4b8f7f547aba0df1afe61b5bb4a3591e22b3cc43 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 19 Oct 2024 18:02:03 +1100 Subject: [PATCH 13/32] coverage: Streamline several names of things in counter creation --- .../src/coverage/counters.rs | 154 ++++++++---------- 1 file changed, 69 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index c78a4924ee68a..9a533ea024d73 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_middle::bug; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; use tracing::{debug, debug_span, instrument}; @@ -58,13 +57,13 @@ pub(super) struct CoverageCounters { counter_increment_sites: IndexVec, /// Coverage counters/expressions that are associated with individual BCBs. - bcb_counters: IndexVec>, + node_counters: IndexVec>, /// Coverage counters/expressions that are associated with the control-flow /// edge between two BCBs. /// /// We currently don't iterate over this map, but if we do in the future, /// switch it back to `FxIndexMap` to avoid query stability hazards. - bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, + edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>, /// Table of expression data, associating each expression ID with its /// corresponding operator (+ or -) and its LHS/RHS operands. @@ -78,20 +77,20 @@ impl CoverageCounters { /// Ensures that each BCB node needing a counter has one, by creating physical /// counters or counter expressions for nodes and edges as required. pub(super) fn make_bcb_counters( - basic_coverage_blocks: &CoverageGraph, + graph: &CoverageGraph, bcb_needs_counter: &BitSet, ) -> Self { - let mut counters = MakeBcbCounters::new(basic_coverage_blocks, bcb_needs_counter); - counters.make_bcb_counters(); + let mut builder = CountersBuilder::new(graph, bcb_needs_counter); + builder.make_bcb_counters(); - counters.coverage_counters + builder.counters } fn with_num_bcbs(num_bcbs: usize) -> Self { Self { counter_increment_sites: IndexVec::new(), - bcb_counters: IndexVec::from_elem_n(None, num_bcbs), - bcb_edge_counters: FxHashMap::default(), + node_counters: IndexVec::from_elem_n(None, num_bcbs), + edge_counters: FxHashMap::default(), expressions: IndexVec::new(), expressions_memo: FxHashMap::default(), } @@ -187,35 +186,31 @@ impl CoverageCounters { self.counter_increment_sites.len() } - fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter { - if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { - bug!( - "attempt to set a BasicCoverageBlock coverage counter more than once; \ - {bcb:?} already had counter {replaced:?}", - ); - } else { - counter_kind - } + fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter { + let existing = self.node_counters[bcb].replace(counter); + assert!( + existing.is_none(), + "node {bcb:?} already has a counter: {existing:?} => {counter:?}" + ); + counter } - fn set_bcb_edge_counter( + fn set_edge_counter( &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, - counter_kind: BcbCounter, + counter: BcbCounter, ) -> BcbCounter { - if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) { - bug!( - "attempt to set an edge counter more than once; from_bcb: \ - {from_bcb:?} already had counter {replaced:?}", - ); - } else { - counter_kind - } + let existing = self.edge_counters.insert((from_bcb, to_bcb), counter); + assert!( + existing.is_none(), + "edge ({from_bcb:?} -> {to_bcb:?}) already has a counter: {existing:?} => {counter:?}" + ); + counter } pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option { - self.bcb_counters[bcb].map(|counter| counter.as_term()) + self.node_counters[bcb].map(|counter| counter.as_term()) } /// Returns an iterator over all the nodes/edges in the coverage graph that @@ -232,7 +227,7 @@ impl CoverageCounters { pub(super) fn bcb_nodes_with_coverage_expressions( &self, ) -> impl Iterator + Captures<'_> { - self.bcb_counters.iter_enumerated().filter_map(|(bcb, &counter_kind)| match counter_kind { + self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter { // Yield the BCB along with its associated expression ID. Some(BcbCounter::Expression { id }) => Some((bcb, id)), // This BCB is associated with a counter or nothing, so skip it. @@ -259,22 +254,20 @@ impl CoverageCounters { } } -/// Helper struct that allows counter creation to inspect the BCB graph. -struct MakeBcbCounters<'a> { - coverage_counters: CoverageCounters, - basic_coverage_blocks: &'a CoverageGraph, +/// Helper struct that allows counter creation to inspect the BCB graph, and +/// the set of nodes that need counters. +struct CountersBuilder<'a> { + counters: CoverageCounters, + graph: &'a CoverageGraph, bcb_needs_counter: &'a BitSet, } -impl<'a> MakeBcbCounters<'a> { - fn new( - basic_coverage_blocks: &'a CoverageGraph, - bcb_needs_counter: &'a BitSet, - ) -> Self { - assert_eq!(basic_coverage_blocks.num_nodes(), bcb_needs_counter.domain_size()); +impl<'a> CountersBuilder<'a> { + fn new(graph: &'a CoverageGraph, bcb_needs_counter: &'a BitSet) -> Self { + assert_eq!(graph.num_nodes(), bcb_needs_counter.domain_size()); Self { - coverage_counters: CoverageCounters::with_num_bcbs(basic_coverage_blocks.num_nodes()), - basic_coverage_blocks, + counters: CoverageCounters::with_num_bcbs(graph.num_nodes()), + graph, bcb_needs_counter, } } @@ -289,7 +282,7 @@ impl<'a> MakeBcbCounters<'a> { // nodes within the loop are visited before visiting any nodes outside // the loop. It also keeps track of which loop(s) the traversal is // currently inside. - let mut traversal = TraverseCoverageGraphWithLoops::new(self.basic_coverage_blocks); + let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph); while let Some(bcb) = traversal.next() { let _span = debug_span!("traversal", ?bcb).entered(); if self.bcb_needs_counter.contains(bcb) { @@ -316,26 +309,26 @@ impl<'a> MakeBcbCounters<'a> { // We might also use that counter to compute one of the out-edge counters. let node_counter = self.get_or_make_node_counter(from_bcb); - let successors = self.basic_coverage_blocks.successors[from_bcb].as_slice(); + let successors = self.graph.successors[from_bcb].as_slice(); // If this node's out-edges won't sum to the node's counter, // then there's no reason to create edge counters here. - if !self.basic_coverage_blocks[from_bcb].is_out_summable { + if !self.graph[from_bcb].is_out_summable { return; } // When choosing which out-edge should be given a counter expression, ignore edges that // already have counters, or could use the existing counter of their target node. let out_edge_has_counter = |to_bcb| { - if self.coverage_counters.bcb_edge_counters.contains_key(&(from_bcb, to_bcb)) { + if self.counters.edge_counters.contains_key(&(from_bcb, to_bcb)) { return true; } - self.basic_coverage_blocks.sole_predecessor(to_bcb) == Some(from_bcb) - && self.coverage_counters.bcb_counters[to_bcb].is_some() + self.graph.sole_predecessor(to_bcb) == Some(from_bcb) + && self.counters.node_counters[to_bcb].is_some() }; // Determine the set of out-edges that could benefit from being given an expression. - let candidate_successors = self.basic_coverage_blocks.successors[from_bcb] + let candidate_successors = self.graph.successors[from_bcb] .iter() .copied() .filter(|&to_bcb| !out_edge_has_counter(to_bcb)) @@ -344,7 +337,7 @@ impl<'a> MakeBcbCounters<'a> { // If there are out-edges without counters, choose one to be given an expression // (computed from this node and the other out-edges) instead of a physical counter. - let Some(expression_to_bcb) = + let Some(target_bcb) = self.choose_out_edge_for_expression(traversal, &candidate_successors) else { return; @@ -357,49 +350,44 @@ impl<'a> MakeBcbCounters<'a> { .iter() .copied() // Skip the chosen edge, since we'll calculate its count from this sum. - .filter(|&to_bcb| to_bcb != expression_to_bcb) + .filter(|&edge_target_bcb| edge_target_bcb != target_bcb) .map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb)) .collect::>(); - let Some(sum_of_all_other_out_edges) = - self.coverage_counters.make_sum(&other_out_edge_counters) + let Some(sum_of_all_other_out_edges) = self.counters.make_sum(&other_out_edge_counters) else { return; }; // Now create an expression for the chosen edge, by taking the counter // for its source node and subtracting the sum of its sibling out-edges. - let expression = self.coverage_counters.make_expression( - node_counter, - Op::Subtract, - sum_of_all_other_out_edges, - ); + let expression = + self.counters.make_expression(node_counter, Op::Subtract, sum_of_all_other_out_edges); - debug!("{expression_to_bcb:?} gets an expression: {expression:?}"); - self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); + debug!("{target_bcb:?} gets an expression: {expression:?}"); + self.counters.set_edge_counter(from_bcb, target_bcb, expression); } #[instrument(level = "debug", skip(self))] fn get_or_make_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { // If the BCB already has a counter, return it. - if let Some(counter_kind) = self.coverage_counters.bcb_counters[bcb] { - debug!("{bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind; + if let Some(counter) = self.counters.node_counters[bcb] { + debug!("{bcb:?} already has a counter: {counter:?}"); + return counter; } let counter = self.make_node_counter_inner(bcb); - self.coverage_counters.set_bcb_counter(bcb, counter) + self.counters.set_node_counter(bcb, counter) } fn make_node_counter_inner(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { // If the node's sole in-edge already has a counter, use that. - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(bcb) - && let Some(&edge_counter) = - self.coverage_counters.bcb_edge_counters.get(&(sole_pred, bcb)) + if let Some(sole_pred) = self.graph.sole_predecessor(bcb) + && let Some(&edge_counter) = self.counters.edge_counters.get(&(sole_pred, bcb)) { return edge_counter; } - let predecessors = self.basic_coverage_blocks.predecessors[bcb].as_slice(); + let predecessors = self.graph.predecessors[bcb].as_slice(); // Handle cases where we can't compute a node's count from its in-edges: // - START_BCB has no in-edges, so taking the sum would panic (or be wrong). @@ -408,7 +396,7 @@ impl<'a> MakeBcbCounters<'a> { // leading to infinite recursion. if predecessors.len() <= 1 || predecessors.contains(&bcb) { debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor"); - let counter = self.coverage_counters.make_phys_node_counter(bcb); + let counter = self.counters.make_phys_node_counter(bcb); debug!(?bcb, ?counter, "node gets a physical counter"); return counter; } @@ -420,10 +408,8 @@ impl<'a> MakeBcbCounters<'a> { .copied() .map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb)) .collect::>(); - let sum_of_in_edges: BcbCounter = self - .coverage_counters - .make_sum(&in_edge_counters) - .expect("there must be at least one in-edge"); + let sum_of_in_edges: BcbCounter = + self.counters.make_sum(&in_edge_counters).expect("there must be at least one in-edge"); debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}"); sum_of_in_edges @@ -436,15 +422,13 @@ impl<'a> MakeBcbCounters<'a> { to_bcb: BasicCoverageBlock, ) -> BcbCounter { // If the edge already has a counter, return it. - if let Some(&counter_kind) = - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) - { - debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind; + if let Some(&counter) = self.counters.edge_counters.get(&(from_bcb, to_bcb)) { + debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter:?}"); + return counter; } let counter = self.make_edge_counter_inner(from_bcb, to_bcb); - self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter) + self.counters.set_edge_counter(from_bcb, to_bcb, counter) } fn make_edge_counter_inner( @@ -454,7 +438,7 @@ impl<'a> MakeBcbCounters<'a> { ) -> BcbCounter { // If the target node has exactly one in-edge (i.e. this one), then just // use the node's counter, since it will have the same value. - if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { + if let Some(sole_pred) = self.graph.sole_predecessor(to_bcb) { assert_eq!(sole_pred, from_bcb); // This call must take care not to invoke `get_or_make_edge` for // this edge, since that would result in infinite recursion! @@ -463,13 +447,13 @@ impl<'a> MakeBcbCounters<'a> { // If the source node has exactly one out-edge (i.e. this one) and would have // the same execution count as that edge, then just use the node's counter. - if let Some(simple_succ) = self.basic_coverage_blocks.simple_successor(from_bcb) { + if let Some(simple_succ) = self.graph.simple_successor(from_bcb) { assert_eq!(simple_succ, to_bcb); return self.get_or_make_node_counter(from_bcb); } // Make a new counter to count this edge. - let counter = self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb); + let counter = self.counters.make_phys_edge_counter(from_bcb, to_bcb); debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); counter } @@ -516,9 +500,9 @@ impl<'a> MakeBcbCounters<'a> { for &target_bcb in candidate_successors { // An edge is a reloop edge if its target dominates any BCB that has // an edge back to the loop header. (Otherwise it's an exit edge.) - let is_reloop_edge = reloop_bcbs.iter().any(|&reloop_bcb| { - self.basic_coverage_blocks.dominates(target_bcb, reloop_bcb) - }); + let is_reloop_edge = reloop_bcbs + .iter() + .any(|&reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb)); if is_reloop_edge { // We found a good out-edge to be given an expression. return Some(target_bcb); From 2372217f82d6f3a5e04b4537bbeee0bce98f008e Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:59:52 -0400 Subject: [PATCH 14/32] Combine entry points for wrapping/unwrapping return types --- .../src/handlers/unwrap_return_type.rs | 414 +++++++----- .../src/handlers/wrap_return_type.rs | 598 ++++++++++-------- .../crates/ide-assists/src/lib.rs | 6 +- 3 files changed, 592 insertions(+), 426 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs index b7f873c7798e2..64d5e2c9b8210 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs @@ -22,9 +22,6 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // fn foo() -> i32 { 42i32 } // ``` -pub(crate) fn unwrap_option_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - unwrap_return_type(acc, ctx, UnwrapperKind::Option) -} // Assist: unwrap_result_return_type // @@ -38,15 +35,8 @@ pub(crate) fn unwrap_option_return_type(acc: &mut Assists, ctx: &AssistContext<' // ``` // fn foo() -> i32 { 42i32 } // ``` -pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - unwrap_return_type(acc, ctx, UnwrapperKind::Result) -} -fn unwrap_return_type( - acc: &mut Assists, - ctx: &AssistContext<'_>, - kind: UnwrapperKind, -) -> Option<()> { +pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let ret_type = ctx.find_node_at_offset::()?; let parent = ret_type.syntax().parent()?; let body = match_ast! { @@ -65,11 +55,12 @@ fn unwrap_return_type( let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { return None; }; - let core_enum = - kind.core_type(FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()))?; - if ret_enum != core_enum { - return None; - } + + let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()); + + let kind = UnwrapperKind::ALL + .iter() + .find(|k| matches!(k.core_type(&famous_defs), Some(core_type) if ret_enum == core_type))?; let happy_type = extract_wrapped_type(type_ref)?; @@ -149,6 +140,8 @@ enum UnwrapperKind { } impl UnwrapperKind { + const ALL: &'static [UnwrapperKind] = &[UnwrapperKind::Option, UnwrapperKind::Result]; + fn assist_id(&self) -> AssistId { let s = match self { UnwrapperKind::Option => "unwrap_option_return_type", @@ -165,7 +158,7 @@ impl UnwrapperKind { } } - fn core_type(&self, famous_defs: FamousDefs<'_, '_>) -> Option { + fn core_type(&self, famous_defs: &FamousDefs<'_, '_>) -> Option { match self { UnwrapperKind::Option => famous_defs.core_option_Option(), UnwrapperKind::Result => famous_defs.core_result_Result(), @@ -209,14 +202,14 @@ fn is_unit_type(ty: &ast::Type) -> bool { #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; + use crate::tests::{check_assist_by_label, check_assist_not_applicable_by_label}; use super::*; #[test] fn unwrap_option_return_type_simple() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -230,13 +223,14 @@ fn foo() -> i32 { return 42i32; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_unit_type() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option<()$0> { @@ -247,11 +241,12 @@ fn foo() -> Option<()$0> { fn foo() { } "#, + "Unwrap Option return type", ); // Unformatted return type - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option<()$0>{ @@ -262,13 +257,14 @@ fn foo() -> Option<()$0>{ fn foo() { } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_none() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -288,13 +284,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_ending_with_parent() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -314,13 +311,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_break_split_tail() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -344,13 +342,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_closure() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() { @@ -368,13 +367,14 @@ fn foo() { }; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_return_type_bad_cursor() { - check_assist_not_applicable( - unwrap_option_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> i32 { @@ -382,13 +382,14 @@ fn foo() -> i32 { return 42i32; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - unwrap_option_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() { @@ -398,24 +399,26 @@ fn foo() { }; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_closure_non_block() { - check_assist_not_applicable( - unwrap_option_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() { || -> i$032 3; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_return_type_already_not_option_std() { - check_assist_not_applicable( - unwrap_option_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -423,13 +426,14 @@ fn foo() -> i32$0 { return 42i32; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_return_type_already_not_option_closure() { - check_assist_not_applicable( - unwrap_option_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() { @@ -439,13 +443,14 @@ fn foo() { }; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() ->$0 Option { @@ -459,13 +464,14 @@ fn foo() -> i32 { 42i32 } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_closure() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() { @@ -483,13 +489,14 @@ fn foo() { }; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_only() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { Some(42i32) } @@ -497,13 +504,14 @@ fn foo() -> Option { Some(42i32) } r#" fn foo() -> i32 { 42i32 } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_block_like() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option$0 { @@ -523,13 +531,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_without_block_closure() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() { @@ -553,13 +562,14 @@ fn foo() { }; } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_nested_if() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option$0 { @@ -587,13 +597,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_await() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option async fn foo() -> Option { @@ -621,13 +632,14 @@ async fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_array() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option<[i32; 3]$0> { Some([1, 2, 3]) } @@ -635,13 +647,14 @@ fn foo() -> Option<[i32; 3]$0> { Some([1, 2, 3]) } r#" fn foo() -> [i32; 3] { [1, 2, 3] } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_cast() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -$0> Option { @@ -669,13 +682,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_block_like_match() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -695,13 +709,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_loop_with_tail() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -723,13 +738,14 @@ fn foo() -> i32 { my_var } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_loop_in_let_stmt() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -747,13 +763,14 @@ fn foo() -> i32 { my_var } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_block_like_match_return_expr() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option$0 { @@ -775,10 +792,11 @@ fn foo() -> i32 { res } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -802,13 +820,14 @@ fn foo() -> i32 { res } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_block_like_match_deeper() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -852,13 +871,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_tail_block_like_early_return() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -878,13 +898,14 @@ fn foo() -> i32 { 53i32 } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_in_tail_position() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(num: i32) -> $0Option { @@ -896,13 +917,14 @@ fn foo(num: i32) -> i32 { return num } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_closure() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> Option { @@ -932,10 +954,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> Option { @@ -977,13 +1000,14 @@ fn foo(the_field: u32) -> u32 { t.unwrap_or_else(|| the_field) } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_simple_with_weird_forms() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -1015,10 +1039,11 @@ fn foo() -> i32 { } } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> Option { @@ -1056,10 +1081,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> Option { @@ -1085,10 +1111,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> Option { @@ -1116,10 +1143,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> Option { @@ -1147,13 +1175,14 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_option_return_type_nested_type() { - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option, result fn foo() -> Option> { @@ -1165,10 +1194,11 @@ fn foo() -> Result { Ok(42) } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option, result fn foo() -> Option, ()>> { @@ -1180,10 +1210,11 @@ fn foo() -> Result, ()> { Err() } "#, + "Unwrap Option return type", ); - check_assist( - unwrap_option_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: option, result, iterators fn foo() -> Option$0> { @@ -1195,13 +1226,14 @@ fn foo() -> impl Iterator { Some(42).into_iter() } "#, + "Unwrap Option return type", ); } #[test] fn unwrap_result_return_type_simple() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1215,13 +1247,14 @@ fn foo() -> i32 { return 42i32; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_unit_type() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result<(), Box> { @@ -1232,11 +1265,12 @@ fn foo() -> Result<(), Box> { fn foo() { } "#, + "Unwrap Result return type", ); // Unformatted return type - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result<(), Box>{ @@ -1247,13 +1281,14 @@ fn foo() -> Result<(), Box>{ fn foo() { } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_ending_with_parent() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result> { @@ -1273,13 +1308,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_break_split_tail() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1303,13 +1339,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_closure() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() { @@ -1327,13 +1364,14 @@ fn foo() { }; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_return_type_bad_cursor() { - check_assist_not_applicable( - unwrap_result_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> i32 { @@ -1341,13 +1379,14 @@ fn foo() -> i32 { return 42i32; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - unwrap_result_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() { @@ -1357,24 +1396,26 @@ fn foo() { }; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_closure_non_block() { - check_assist_not_applicable( - unwrap_result_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() { || -> i$032 3; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_return_type_already_not_result_std() { - check_assist_not_applicable( - unwrap_result_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1382,13 +1423,14 @@ fn foo() -> i32$0 { return 42i32; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_return_type_already_not_result_closure() { - check_assist_not_applicable( - unwrap_result_return_type, + check_assist_not_applicable_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() { @@ -1398,13 +1440,14 @@ fn foo() { }; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() ->$0 Result { @@ -1418,13 +1461,14 @@ fn foo() -> i32 { 42i32 } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_closure() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() { @@ -1442,13 +1486,14 @@ fn foo() { }; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_only() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { Ok(42i32) } @@ -1456,13 +1501,14 @@ fn foo() -> Result { Ok(42i32) } r#" fn foo() -> i32 { 42i32 } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_block_like() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result$0 { @@ -1482,13 +1528,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_without_block_closure() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() { @@ -1512,13 +1559,14 @@ fn foo() { }; } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_nested_if() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result$0 { @@ -1546,13 +1594,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_await() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result async fn foo() -> Result { @@ -1580,13 +1629,14 @@ async fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_array() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result<[i32; 3]$0> { Ok([1, 2, 3]) } @@ -1594,13 +1644,14 @@ fn foo() -> Result<[i32; 3]$0> { Ok([1, 2, 3]) } r#" fn foo() -> [i32; 3] { [1, 2, 3] } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_cast() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -$0> Result { @@ -1628,13 +1679,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_block_like_match() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1654,13 +1706,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_loop_with_tail() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1682,13 +1735,14 @@ fn foo() -> i32 { my_var } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_loop_in_let_stmt() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1706,13 +1760,14 @@ fn foo() -> i32 { my_var } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_block_like_match_return_expr() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result$0 { @@ -1734,10 +1789,11 @@ fn foo() -> i32 { res } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1761,13 +1817,14 @@ fn foo() -> i32 { res } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_block_like_match_deeper() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1811,13 +1868,14 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_tail_block_like_early_return() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1837,13 +1895,14 @@ fn foo() -> i32 { 53i32 } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_in_tail_position() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(num: i32) -> $0Result { @@ -1855,13 +1914,14 @@ fn foo(num: i32) -> i32 { return num } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_closure() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> Result { @@ -1891,10 +1951,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> Result { @@ -1936,13 +1997,14 @@ fn foo(the_field: u32) -> u32 { t.unwrap_or_else(|| the_field) } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_simple_with_weird_forms() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1974,10 +2036,11 @@ fn foo() -> i32 { } } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> Result { @@ -2015,10 +2078,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> Result { @@ -2044,10 +2108,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> Result { @@ -2075,10 +2140,11 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> Result { @@ -2106,13 +2172,14 @@ fn foo(the_field: u32) -> u32 { the_field } "#, + "Unwrap Result return type", ); } #[test] fn unwrap_result_return_type_nested_type() { - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result, option fn foo() -> Result, ()> { @@ -2124,10 +2191,11 @@ fn foo() -> Option { Some(42) } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result, option fn foo() -> Result>, ()> { @@ -2139,10 +2207,11 @@ fn foo() -> Option> { None } "#, + "Unwrap Result return type", ); - check_assist( - unwrap_result_return_type, + check_assist_by_label( + unwrap_return_type, r#" //- minicore: result, option, iterators fn foo() -> Result$0, ()> { @@ -2154,6 +2223,7 @@ fn foo() -> impl Iterator { Some(42).into_iter() } "#, + "Unwrap Result return type", ); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs index e6e1857a3f767..2d918a5b1c19f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -2,6 +2,7 @@ use std::iter; use hir::HasSource; use ide_db::{ + assists::GroupLabel, famous_defs::FamousDefs, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; @@ -25,9 +26,6 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // fn foo() -> Option { Some(42i32) } // ``` -pub(crate) fn wrap_return_type_in_option(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - wrap_return_type(acc, ctx, WrapperKind::Option) -} // Assist: wrap_return_type_in_result // @@ -41,8 +39,97 @@ pub(crate) fn wrap_return_type_in_option(acc: &mut Assists, ctx: &AssistContext< // ``` // fn foo() -> Result { Ok(42i32) } // ``` -pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - wrap_return_type(acc, ctx, WrapperKind::Result) + +pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let ret_type = ctx.find_node_at_offset::()?; + let parent = ret_type.syntax().parent()?; + let body = match_ast! { + match parent { + ast::Fn(func) => func.body()?, + ast::ClosureExpr(closure) => match closure.body()? { + Expr::BlockExpr(block) => block, + // closures require a block when a return type is specified + _ => return None, + }, + _ => return None, + } + }; + + let type_ref = &ret_type.ty()?; + let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); + let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()); + + for kind in WrapperKind::ALL { + let Some(core_wrapper) = kind.core_type(&famous_defs) else { + continue; + }; + + if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) { + // The return type is already wrapped + cov_mark::hit!(wrap_return_type_simple_return_type_already_wrapped); + continue; + } + + acc.add_group( + &GroupLabel("Wrap return type in...".into()), + kind.assist_id(), + kind.label(), + type_ref.syntax().text_range(), + |edit| { + let alias = wrapper_alias(ctx, &core_wrapper, type_ref, kind.symbol()); + let new_return_ty = + alias.unwrap_or_else(|| kind.wrap_type(type_ref)).clone_for_update(); + + let body = edit.make_mut(ast::Expr::BlockExpr(body.clone())); + + let mut exprs_to_wrap = Vec::new(); + let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); + walk_expr(&body, &mut |expr| { + if let Expr::ReturnExpr(ret_expr) = expr { + if let Some(ret_expr_arg) = &ret_expr.expr() { + for_each_tail_expr(ret_expr_arg, tail_cb); + } + } + }); + for_each_tail_expr(&body, tail_cb); + + for ret_expr_arg in exprs_to_wrap { + let happy_wrapped = make::expr_call( + make::expr_path(make::ext::ident_path(kind.happy_ident())), + make::arg_list(iter::once(ret_expr_arg.clone())), + ) + .clone_for_update(); + ted::replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); + } + + let old_return_ty = edit.make_mut(type_ref.clone()); + ted::replace(old_return_ty.syntax(), new_return_ty.syntax()); + + if let WrapperKind::Result = kind { + // Add a placeholder snippet at the first generic argument that doesn't equal the return type. + // This is normally the error type, but that may not be the case when we inserted a type alias. + let args = + new_return_ty.syntax().descendants().find_map(ast::GenericArgList::cast); + let error_type_arg = args.and_then(|list| { + list.generic_args().find(|arg| match arg { + ast::GenericArg::TypeArg(_) => { + arg.syntax().text() != type_ref.syntax().text() + } + ast::GenericArg::LifetimeArg(_) => false, + _ => true, + }) + }); + if let Some(error_type_arg) = error_type_arg { + if let Some(cap) = ctx.config.snippet_cap { + edit.add_placeholder_snippet(cap, error_type_arg); + } + } + } + }, + ); + } + + Some(()) } enum WrapperKind { @@ -51,6 +138,8 @@ enum WrapperKind { } impl WrapperKind { + const ALL: &'static [WrapperKind] = &[WrapperKind::Option, WrapperKind::Result]; + fn assist_id(&self) -> AssistId { let s = match self { WrapperKind::Option => "wrap_return_type_in_option", @@ -74,7 +163,7 @@ impl WrapperKind { } } - fn core_type(&self, famous_defs: FamousDefs<'_, '_>) -> Option { + fn core_type(&self, famous_defs: &FamousDefs<'_, '_>) -> Option { match self { WrapperKind::Option => famous_defs.core_option_Option(), WrapperKind::Result => famous_defs.core_result_Result(), @@ -96,81 +185,6 @@ impl WrapperKind { } } -fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>, kind: WrapperKind) -> Option<()> { - let ret_type = ctx.find_node_at_offset::()?; - let parent = ret_type.syntax().parent()?; - let body = match_ast! { - match parent { - ast::Fn(func) => func.body()?, - ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, - // closures require a block when a return type is specified - _ => return None, - }, - _ => return None, - } - }; - - let type_ref = &ret_type.ty()?; - let core_wrapper = - kind.core_type(FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()))?; - - let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); - if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) { - // The return type is already wrapped - cov_mark::hit!(wrap_return_type_simple_return_type_already_wrapped); - return None; - } - - acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |edit| { - let alias = wrapper_alias(ctx, &core_wrapper, type_ref, kind.symbol()); - let new_return_ty = alias.unwrap_or_else(|| kind.wrap_type(type_ref)).clone_for_update(); - - let body = edit.make_mut(ast::Expr::BlockExpr(body)); - - let mut exprs_to_wrap = Vec::new(); - let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } - } - }); - for_each_tail_expr(&body, tail_cb); - - for ret_expr_arg in exprs_to_wrap { - let happy_wrapped = make::expr_call( - make::expr_path(make::ext::ident_path(kind.happy_ident())), - make::arg_list(iter::once(ret_expr_arg.clone())), - ) - .clone_for_update(); - ted::replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); - } - - let old_return_ty = edit.make_mut(type_ref.clone()); - ted::replace(old_return_ty.syntax(), new_return_ty.syntax()); - - if let WrapperKind::Result = kind { - // Add a placeholder snippet at the first generic argument that doesn't equal the return type. - // This is normally the error type, but that may not be the case when we inserted a type alias. - let args = new_return_ty.syntax().descendants().find_map(ast::GenericArgList::cast); - let error_type_arg = args.and_then(|list| { - list.generic_args().find(|arg| match arg { - ast::GenericArg::TypeArg(_) => arg.syntax().text() != type_ref.syntax().text(), - ast::GenericArg::LifetimeArg(_) => false, - _ => true, - }) - }); - if let Some(error_type_arg) = error_type_arg { - if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, error_type_arg); - } - } - } - }) -} - // Try to find an wrapper type alias in the current scope (shadowing the default). fn wrapper_alias( ctx: &AssistContext<'_>, @@ -232,14 +246,14 @@ fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; + use crate::tests::{check_assist_by_label, check_assist_not_applicable_by_label}; use super::*; #[test] fn wrap_return_type_in_option_simple() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i3$02 { @@ -253,13 +267,14 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_break_split_tail() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i3$02 { @@ -283,13 +298,14 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_closure() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() { @@ -307,13 +323,14 @@ fn foo() { }; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_return_type_bad_cursor() { - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32 { @@ -321,13 +338,14 @@ fn foo() -> i32 { return 42i32; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option fn foo() { @@ -337,24 +355,26 @@ fn foo() { }; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_closure_non_block() { - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option fn foo() { || -> i$032 3; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_return_type_already_option_std() { - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> core::option::Option { @@ -362,14 +382,15 @@ fn foo() -> core::option::Option { return 42i32; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_return_type_already_option() { cov_mark::check!(wrap_return_type_simple_return_type_already_wrapped); - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> Option { @@ -377,13 +398,14 @@ fn foo() -> Option { return 42i32; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_return_type_already_option_closure() { - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option fn foo() { @@ -393,13 +415,14 @@ fn foo() { }; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_cursor() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> $0i32 { @@ -413,13 +436,14 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() ->$0 i32 { @@ -433,13 +457,14 @@ fn foo() -> Option { Some(42i32) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_closure() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() { @@ -457,13 +482,14 @@ fn foo() { }; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_only() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { 42i32 } @@ -471,13 +497,14 @@ fn foo() -> i32$0 { 42i32 } r#" fn foo() -> Option { Some(42i32) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_block_like() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -497,13 +524,14 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_without_block_closure() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() { @@ -527,13 +555,14 @@ fn foo() { }; } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_nested_if() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -561,13 +590,14 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_await() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option async fn foo() -> i$032 { @@ -595,13 +625,14 @@ async fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_array() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> [i32;$0 3] { [1, 2, 3] } @@ -609,13 +640,14 @@ fn foo() -> [i32;$0 3] { [1, 2, 3] } r#" fn foo() -> Option<[i32; 3]> { Some([1, 2, 3]) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_cast() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -$0> i32 { @@ -643,13 +675,14 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_block_like_match() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -669,13 +702,14 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_loop_with_tail() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -697,13 +731,14 @@ fn foo() -> Option { Some(my_var) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_loop_in_let_stmt() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -721,13 +756,14 @@ fn foo() -> Option { Some(my_var) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_block_like_match_return_expr() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -749,10 +785,11 @@ fn foo() -> Option { Some(res) } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -776,13 +813,14 @@ fn foo() -> Option { Some(res) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_block_like_match_deeper() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -826,13 +864,14 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_tail_block_like_early_return() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i$032 { @@ -852,13 +891,14 @@ fn foo() -> Option { Some(53i32) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_in_option_tail_position() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(num: i32) -> $0i32 { @@ -870,13 +910,14 @@ fn foo(num: i32) -> Option { return Some(num) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_closure() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(the_field: u32) ->$0 u32 { @@ -906,10 +947,11 @@ fn foo(the_field: u32) -> Option { Some(the_field) } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> u32$0 { @@ -951,13 +993,14 @@ fn foo(the_field: u32) -> Option { Some(t.unwrap_or_else(|| the_field)) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_option_simple_with_weird_forms() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i32$0 { @@ -989,10 +1032,11 @@ fn foo() -> Option { } } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> u32$0 { @@ -1030,10 +1074,11 @@ fn foo(the_field: u32) -> Option { Some(the_field) } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> u3$02 { @@ -1059,10 +1104,11 @@ fn foo(the_field: u32) -> Option { Some(the_field) } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> u32$0 { @@ -1090,10 +1136,11 @@ fn foo(the_field: u32) -> Option { Some(the_field) } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo(the_field: u32) -> $0u32 { @@ -1121,13 +1168,14 @@ fn foo(the_field: u32) -> Option { Some(the_field) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_local_option_type() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option type Option = core::option::Option; @@ -1143,10 +1191,11 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option type Option2 = core::option::Option; @@ -1162,13 +1211,14 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_imported_local_option_type() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option mod some_module { @@ -1192,10 +1242,11 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option mod some_module { @@ -1219,13 +1270,14 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_local_option_type_from_function_body() { - check_assist( - wrap_return_type_in_option, + check_assist_by_label( + wrap_return_type, r#" //- minicore: option fn foo() -> i3$02 { @@ -1239,13 +1291,14 @@ fn foo() -> Option { Some(0) } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_local_option_type_already_using_alias() { - check_assist_not_applicable( - wrap_return_type_in_option, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: option pub type Option = core::option::Option; @@ -1254,13 +1307,14 @@ fn foo() -> Option { return Some(42i32); } "#, + WrapperKind::Option.label(), ); } #[test] fn wrap_return_type_in_result_simple() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i3$02 { @@ -1274,13 +1328,14 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_break_split_tail() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i3$02 { @@ -1304,13 +1359,14 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_closure() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() { @@ -1328,13 +1384,14 @@ fn foo() { }; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_return_type_bad_cursor() { - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32 { @@ -1342,13 +1399,14 @@ fn foo() -> i32 { return 42i32; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_return_type_bad_cursor_closure() { - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result fn foo() { @@ -1358,24 +1416,26 @@ fn foo() { }; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_closure_non_block() { - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result fn foo() { || -> i$032 3; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_return_type_already_result_std() { - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> core::result::Result { @@ -1383,14 +1443,15 @@ fn foo() -> core::result::Result { return 42i32; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_return_type_already_result() { cov_mark::check!(wrap_return_type_simple_return_type_already_wrapped); - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> Result { @@ -1398,13 +1459,14 @@ fn foo() -> Result { return 42i32; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_return_type_already_result_closure() { - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result fn foo() { @@ -1414,13 +1476,14 @@ fn foo() { }; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_cursor() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> $0i32 { @@ -1434,13 +1497,14 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() ->$0 i32 { @@ -1454,13 +1518,14 @@ fn foo() -> Result { Ok(42i32) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_closure() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() { @@ -1478,13 +1543,14 @@ fn foo() { }; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_only() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { 42i32 } @@ -1492,13 +1558,14 @@ fn foo() -> i32$0 { 42i32 } r#" fn foo() -> Result { Ok(42i32) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_block_like() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1518,13 +1585,14 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_without_block_closure() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() { @@ -1548,13 +1616,14 @@ fn foo() { }; } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_nested_if() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1582,13 +1651,14 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_await() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result async fn foo() -> i$032 { @@ -1616,13 +1686,14 @@ async fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_array() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> [i32;$0 3] { [1, 2, 3] } @@ -1630,13 +1701,14 @@ fn foo() -> [i32;$0 3] { [1, 2, 3] } r#" fn foo() -> Result<[i32; 3], ${0:_}> { Ok([1, 2, 3]) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_cast() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -$0> i32 { @@ -1664,13 +1736,14 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_block_like_match() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1690,13 +1763,14 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_loop_with_tail() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1718,13 +1792,14 @@ fn foo() -> Result { Ok(my_var) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_loop_in_let_stmt() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1742,13 +1817,14 @@ fn foo() -> Result { Ok(my_var) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_block_like_match_return_expr() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1770,10 +1846,11 @@ fn foo() -> Result { Ok(res) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1797,13 +1874,14 @@ fn foo() -> Result { Ok(res) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_block_like_match_deeper() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -1847,13 +1925,14 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_tail_block_like_early_return() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i$032 { @@ -1873,13 +1952,14 @@ fn foo() -> Result { Ok(53i32) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_in_result_tail_position() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(num: i32) -> $0i32 { @@ -1891,13 +1971,14 @@ fn foo(num: i32) -> Result { return Ok(num) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_closure() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(the_field: u32) ->$0 u32 { @@ -1927,10 +2008,11 @@ fn foo(the_field: u32) -> Result { Ok(the_field) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> u32$0 { @@ -1972,13 +2054,14 @@ fn foo(the_field: u32) -> Result { Ok(t.unwrap_or_else(|| the_field)) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_result_simple_with_weird_forms() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i32$0 { @@ -2010,10 +2093,11 @@ fn foo() -> Result { } } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> u32$0 { @@ -2051,10 +2135,11 @@ fn foo(the_field: u32) -> Result { Ok(the_field) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> u3$02 { @@ -2080,10 +2165,11 @@ fn foo(the_field: u32) -> Result { Ok(the_field) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> u32$0 { @@ -2111,10 +2197,11 @@ fn foo(the_field: u32) -> Result { Ok(the_field) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo(the_field: u32) -> $0u32 { @@ -2142,13 +2229,14 @@ fn foo(the_field: u32) -> Result { Ok(the_field) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_local_result_type() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result type Result = core::result::Result; @@ -2164,10 +2252,11 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result type Result2 = core::result::Result; @@ -2183,13 +2272,14 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_imported_local_result_type() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result mod some_module { @@ -2213,10 +2303,11 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result mod some_module { @@ -2240,13 +2331,14 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_local_result_type_from_function_body() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result fn foo() -> i3$02 { @@ -2260,13 +2352,14 @@ fn foo() -> Result { Ok(0) } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_local_result_type_already_using_alias() { - check_assist_not_applicable( - wrap_return_type_in_result, + check_assist_not_applicable_by_label( + wrap_return_type, r#" //- minicore: result pub type Result = core::result::Result; @@ -2275,13 +2368,14 @@ fn foo() -> Result { return Ok(42i32); } "#, + WrapperKind::Result.label(), ); } #[test] fn wrap_return_type_in_local_result_type_multiple_generics() { - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result type Result = core::result::Result; @@ -2297,10 +2391,11 @@ fn foo() -> Result { Ok(0) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result type Result = core::result::Result, ()>; @@ -2316,10 +2411,11 @@ fn foo() -> Result { Ok(0) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result type Result<'a, T, E> = core::result::Result, &'a ()>; @@ -2335,10 +2431,11 @@ fn foo() -> Result<'_, i32, ${0:_}> { Ok(0) } "#, + WrapperKind::Result.label(), ); - check_assist( - wrap_return_type_in_result, + check_assist_by_label( + wrap_return_type, r#" //- minicore: result type Result = core::result::Result, Bar>; @@ -2354,6 +2451,7 @@ fn foo() -> Result { Ok(0) } "#, + WrapperKind::Result.label(), ); } } 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 8114888d6c3fa..22620816d5043 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -355,12 +355,10 @@ mod handlers { unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, unwrap_block::unwrap_block, - unwrap_return_type::unwrap_option_return_type, - unwrap_return_type::unwrap_result_return_type, + unwrap_return_type::unwrap_return_type, unwrap_tuple::unwrap_tuple, unqualify_method_call::unqualify_method_call, - wrap_return_type::wrap_return_type_in_option, - wrap_return_type::wrap_return_type_in_result, + wrap_return_type::wrap_return_type, wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr, // These are manually sorted for better priorities. By default, From ccfc8e20633ed94ef2be849e68a4752e99dac483 Mon Sep 17 00:00:00 2001 From: roife Date: Sun, 20 Oct 2024 16:45:38 +0800 Subject: [PATCH 15/32] feat: initial support for safe_kw in extern blocks --- .../rust-analyzer/crates/hir-def/src/data.rs | 4 + .../crates/hir-def/src/item_tree.rs | 1 + .../crates/hir-def/src/item_tree/lower.rs | 3 + .../crates/hir-def/src/item_tree/pretty.rs | 3 + .../rust-analyzer/crates/hir-ty/src/utils.rs | 12 +- .../src/handlers/missing_unsafe.rs | 4 +- .../crates/parser/src/grammar/items.rs | 6 + .../parser/src/syntax_kind/generated.rs | 6 +- ...73_safe_declarations_in_extern_blocks.rast | 208 ++++++++++++++++++ ...0073_safe_declarations_in_extern_blocks.rs | 17 ++ .../rust-analyzer/crates/syntax/rust.ungram | 3 +- .../crates/syntax/src/ast/generated/nodes.rs | 6 + 12 files changed, 264 insertions(+), 9 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 3ecb57c75671f..f2c49813fa0ee 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -148,6 +148,10 @@ impl FunctionData { self.flags.contains(FnFlags::HAS_UNSAFE_KW) } + pub fn is_safe(&self) -> bool { + self.flags.contains(FnFlags::HAS_SAFE_KW) + } + pub fn is_varargs(&self) -> bool { self.flags.contains(FnFlags::IS_VARARGS) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index f16230e1dc311..4bee7eeb9e520 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -754,6 +754,7 @@ bitflags::bitflags! { const HAS_ASYNC_KW = 1 << 4; const HAS_UNSAFE_KW = 1 << 5; const IS_VARARGS = 1 << 6; + const HAS_SAFE_KW = 1 << 7; } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 7aac383ab4796..1d8d236d971fe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -440,6 +440,9 @@ impl<'a> Ctx<'a> { if func.unsafe_token().is_some() { flags |= FnFlags::HAS_UNSAFE_KW; } + if func.safe_token().is_some() { + flags |= FnFlags::HAS_SAFE_KW; + } if has_var_args { flags |= FnFlags::IS_VARARGS; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index b5a65abce8696..5ab4718a36b91 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -278,6 +278,9 @@ impl Printer<'_> { if flags.contains(FnFlags::HAS_UNSAFE_KW) { w!(self, "unsafe "); } + if flags.contains(FnFlags::HAS_SAFE_KW) { + w!(self, "safe "); + } if let Some(abi) = abi { w!(self, "extern \"{}\" ", abi); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index d1ce68da6d6d8..10252ce6f3e49 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -257,10 +257,12 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { return true; } - match func.lookup(db.upcast()).container { + let loc = func.lookup(db.upcast()); + match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - // Function in an `extern` block are always unsafe to call, except when it has - // `"rust-intrinsic"` ABI there are a few exceptions. + // Function in an `extern` block are always unsafe to call, except when + // it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a + // few exceptions. let id = block.lookup(db.upcast()).id; let is_intrinsic = @@ -270,8 +272,8 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute !data.attrs.by_key(&sym::rustc_safe_intrinsic).exists() } else { - // Extern items are always unsafe - true + // Extern items without `safe` modifier are always unsafe + !db.function_data(func).is_safe() } } _ => false, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 5b43f4b2af3d0..a53dd31286fc3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -554,7 +554,7 @@ fn main() { r#" //- /ed2021.rs crate:ed2021 edition:2021 #[rustc_deprecated_safe_2024] -unsafe fn safe() -> u8 { +unsafe fn safe_fn() -> u8 { 0 } //- /ed2024.rs crate:ed2024 edition:2024 @@ -564,7 +564,7 @@ unsafe fn not_safe() -> u8 { } //- /main.rs crate:main deps:ed2021,ed2024 fn main() { - ed2021::safe(); + ed2021::safe_fn(); ed2024::not_safe(); //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 4e2a50d7a1fe7..5f46093da523e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -135,6 +135,11 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { has_mods = true; } + if p.at(T![safe]) { + p.eat(T![safe]); + has_mods = true; + } + if p.at(T![extern]) { has_extern = true; has_mods = true; @@ -189,6 +194,7 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { T![fn] => fn_(p, m), T![const] if p.nth(1) != T!['{'] => consts::konst(p, m), + T![static] if matches!(p.nth(1), IDENT | T![_] | T![mut]) => consts::static_(p, m), T![trait] => traits::trait_(p, m), T![impl] => traits::impl_(p, m), diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 288a07ef44dc6..39d9d7e340b1c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -94,6 +94,7 @@ pub enum SyntaxKind { PUB_KW, REF_KW, RETURN_KW, + SAFE_KW, SELF_KW, STATIC_KW, STRUCT_KW, @@ -364,6 +365,7 @@ impl SyntaxKind { | PUB_KW | REF_KW | RETURN_KW + | SAFE_KW | SELF_KW | STATIC_KW | STRUCT_KW @@ -458,6 +460,7 @@ impl SyntaxKind { | PUB_KW | REF_KW | RETURN_KW + | SAFE_KW | SELF_KW | STATIC_KW | STRUCT_KW @@ -614,6 +617,7 @@ impl SyntaxKind { "pub" => PUB_KW, "ref" => REF_KW, "return" => RETURN_KW, + "safe" => SAFE_KW, "self" => SELF_KW, "static" => STATIC_KW, "struct" => STRUCT_KW, @@ -707,4 +711,4 @@ impl SyntaxKind { } } #[macro_export] -macro_rules ! T { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } +macro_rules ! T { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rast new file mode 100644 index 0000000000000..b3d9e5580675e --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rast @@ -0,0 +1,208 @@ +SOURCE_FILE + EXTERN_BLOCK + UNSAFE_KW "unsafe" + WHITESPACE " " + ABI + EXTERN_KW "extern" + WHITESPACE " " + EXTERN_ITEM_LIST + L_CURLY "{" + WHITESPACE "\n " + FN + COMMENT "// sqrt (from libm) may be called with any `f64`" + WHITESPACE "\n " + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + SAFE_KW "safe" + WHITESPACE " " + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "sqrt" + PARAM_LIST + L_PAREN "(" + PARAM + IDENT_PAT + NAME + IDENT "x" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "f64" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "f64" + SEMICOLON ";" + WHITESPACE "\n\n " + FN + COMMENT "// strlen (from libc) requires a valid pointer," + WHITESPACE "\n " + COMMENT "// so we mark it as being an unsafe fn" + WHITESPACE "\n " + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + UNSAFE_KW "unsafe" + WHITESPACE " " + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "strlen" + PARAM_LIST + L_PAREN "(" + PARAM + IDENT_PAT + NAME + IDENT "p" + COLON ":" + WHITESPACE " " + PTR_TYPE + STAR "*" + CONST_KW "const" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "c_char" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "usize" + SEMICOLON ";" + WHITESPACE "\n\n " + FN + COMMENT "// this function doesn't say safe or unsafe, so it defaults to unsafe" + WHITESPACE "\n " + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "free" + PARAM_LIST + L_PAREN "(" + PARAM + IDENT_PAT + NAME + IDENT "p" + COLON ":" + WHITESPACE " " + PTR_TYPE + STAR "*" + MUT_KW "mut" + WHITESPACE " " + PATH_TYPE + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "core" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "ffi" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "c_void" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n\n " + STATIC + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + SAFE_KW "safe" + WHITESPACE " " + STATIC_KW "static" + WHITESPACE " " + MUT_KW "mut" + WHITESPACE " " + NAME + IDENT "COUNTER" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + SEMICOLON ";" + WHITESPACE "\n\n " + STATIC + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + UNSAFE_KW "unsafe" + WHITESPACE " " + STATIC_KW "static" + WHITESPACE " " + NAME + IDENT "IMPORTANT_BYTES" + COLON ":" + WHITESPACE " " + ARRAY_TYPE + L_BRACK "[" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "u8" + SEMICOLON ";" + WHITESPACE " " + CONST_ARG + LITERAL + INT_NUMBER "256" + R_BRACK "]" + SEMICOLON ";" + WHITESPACE "\n\n " + STATIC + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + SAFE_KW "safe" + WHITESPACE " " + STATIC_KW "static" + WHITESPACE " " + NAME + IDENT "LINES" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "SyncUnsafeCell" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rs new file mode 100644 index 0000000000000..267a128649c7b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0073_safe_declarations_in_extern_blocks.rs @@ -0,0 +1,17 @@ +unsafe extern { + // sqrt (from libm) may be called with any `f64` + pub safe fn sqrt(x: f64) -> f64; + + // strlen (from libc) requires a valid pointer, + // so we mark it as being an unsafe fn + pub unsafe fn strlen(p: *const c_char) -> usize; + + // this function doesn't say safe or unsafe, so it defaults to unsafe + pub fn free(p: *mut core::ffi::c_void); + + pub safe static mut COUNTER: i32; + + pub unsafe static IMPORTANT_BYTES: [u8; 256]; + + pub safe static LINES: SyncUnsafeCell; +} diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 52ad439e4decc..90441c27f6286 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -190,7 +190,7 @@ UseTreeList = Fn = Attr* Visibility? - 'default'? 'const'? 'async'? 'gen'? 'unsafe'? Abi? + 'default'? 'const'? 'async'? 'gen'? 'unsafe'? 'safe'? Abi? 'fn' Name GenericParamList? ParamList RetType? WhereClause? (body:BlockExpr | ';') @@ -284,6 +284,7 @@ Const = Static = Attr* Visibility? + 'unsafe'? 'safe'? 'static' 'mut'? Name ':' Type ('=' body:Expr)? ';' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index c81a19f3bda41..4f8bff489cfbd 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -668,6 +668,8 @@ impl Fn { #[inline] pub fn gen_token(&self) -> Option { support::token(&self.syntax, T![gen]) } #[inline] + pub fn safe_token(&self) -> Option { support::token(&self.syntax, T![safe]) } + #[inline] pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } } @@ -1761,7 +1763,11 @@ impl Static { #[inline] pub fn mut_token(&self) -> Option { support::token(&self.syntax, T![mut]) } #[inline] + pub fn safe_token(&self) -> Option { support::token(&self.syntax, T![safe]) } + #[inline] pub fn static_token(&self) -> Option { support::token(&self.syntax, T![static]) } + #[inline] + pub fn unsafe_token(&self) -> Option { support::token(&self.syntax, T![unsafe]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] From 1b90ae48926850fbada77692c48f1fd5eee85cd8 Mon Sep 17 00:00:00 2001 From: roife Date: Sun, 20 Oct 2024 19:48:15 +0800 Subject: [PATCH 16/32] fix: do not emit unsafe diagnositcs for safe statics in extern blocks --- .../rust-analyzer/crates/hir-def/src/data.rs | 4 +++ .../crates/hir-def/src/item_tree.rs | 3 ++ .../crates/hir-def/src/item_tree/lower.rs | 5 ++- .../crates/hir-def/src/item_tree/pretty.rs | 16 ++++++++- .../hir-ty/src/diagnostics/unsafe_check.rs | 2 +- .../src/handlers/missing_unsafe.rs | 35 +++++++++++++++++++ 6 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index f2c49813fa0ee..263fad51d78ec 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -571,6 +571,8 @@ pub struct StaticData { pub visibility: RawVisibility, pub mutable: bool, pub is_extern: bool, + pub has_safe_kw: bool, + pub has_unsafe_kw: bool, } impl StaticData { @@ -585,6 +587,8 @@ impl StaticData { visibility: item_tree[statik.visibility].clone(), mutable: statik.mutable, is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)), + has_safe_kw: statik.has_safe_kw, + has_unsafe_kw: statik.has_unsafe_kw, }) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 4bee7eeb9e520..7cb833fdce7c0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -823,7 +823,10 @@ pub struct Const { pub struct Static { pub name: Name, pub visibility: RawVisibilityId, + // TODO: use bitflags when we have more flags pub mutable: bool, + pub has_safe_kw: bool, + pub has_unsafe_kw: bool, pub type_ref: Interned, pub ast_id: FileAstId, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 1d8d236d971fe..431a7f66f405d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -487,8 +487,11 @@ impl<'a> Ctx<'a> { let type_ref = self.lower_type_ref_opt(static_.ty()); let visibility = self.lower_visibility(static_); let mutable = static_.mut_token().is_some(); + let has_safe_kw = static_.safe_token().is_some(); + let has_unsafe_kw = static_.unsafe_token().is_some(); let ast_id = self.source_ast_id_map.ast_id(static_); - let res = Static { name, visibility, mutable, type_ref, ast_id }; + let res = + Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw }; Some(id(self.data().statics.alloc(res))) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 5ab4718a36b91..9dce28b2e4927 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -382,9 +382,23 @@ impl Printer<'_> { wln!(self, " = _;"); } ModItem::Static(it) => { - let Static { name, visibility, mutable, type_ref, ast_id } = &self.tree[it]; + let Static { + name, + visibility, + mutable, + type_ref, + ast_id, + has_safe_kw, + has_unsafe_kw, + } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); + if *has_safe_kw { + w!(self, "safe "); + } + if *has_unsafe_kw { + w!(self, "unsafe "); + } w!(self, "static "); if *mutable { w!(self, "mut "); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index ff45c725c73cd..bcfc37c86711e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -89,7 +89,7 @@ fn walk_unsafe( let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { let static_data = db.static_data(id); - if static_data.mutable || static_data.is_extern { + if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block }); } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index a53dd31286fc3..cc0f4bfccc9a8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -595,4 +595,39 @@ unsafe fn foo(p: *mut i32) { "#, ) } + + #[test] + fn no_unsafe_diagnostic_with_safe_kw() { + check_diagnostics( + r#" +unsafe extern { + pub safe fn f(); + + pub unsafe fn g(); + + pub fn h(); + + pub safe static S1: i32; + + pub unsafe static S2: i32; + + pub static S3: i32; +} + +fn main() { + f(); + g(); + //^^^💡 error: this operation is unsafe and requires an unsafe function or block + h(); + //^^^💡 error: this operation is unsafe and requires an unsafe function or block + + let _ = S1; + let _ = S2; + //^^💡 error: this operation is unsafe and requires an unsafe function or block + let _ = S3; + //^^💡 error: this operation is unsafe and requires an unsafe function or block +} +"#, + ); + } } From 3bbf1b257f4905ab2f5ca157c35b8f8ca22fecab Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 20 Oct 2024 18:50:05 +0300 Subject: [PATCH 17/32] Update Cargo.lock --- src/tools/rust-analyzer/Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index a99294033b44d..da65d8804949a 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -731,7 +731,7 @@ dependencies = [ "indexmap", "itertools", "limit", - "line-index 0.1.1", + "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "memchr", "nohash-hasher", "parser", @@ -939,20 +939,20 @@ version = "0.0.0" [[package]] name = "line-index" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d61795376ae2683928c218fda7d7d7db136fd38c06b7552904667f0d55580a" +version = "0.1.2" dependencies = [ "nohash-hasher", + "oorandom", "text-size", ] [[package]] name = "line-index" version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e27e0ed5a392a7f5ba0b3808a2afccff16c64933312c84b57618b49d1209bd2" dependencies = [ "nohash-hasher", - "oorandom", "text-size", ] From 8183f6b4739884b9cce0e29eaaf5d42643e5f540 Mon Sep 17 00:00:00 2001 From: roife Date: Mon, 21 Oct 2024 02:56:21 +0800 Subject: [PATCH 18/32] fix: classify `safe` as a contextual kw --- src/tools/rust-analyzer/crates/hir-ty/src/utils.rs | 2 +- .../ide-diagnostics/src/handlers/missing_unsafe.rs | 4 ++-- .../rust-analyzer/crates/parser/src/grammar/items.rs | 4 ++-- .../crates/parser/src/syntax_kind/generated.rs | 10 +++++----- .../rust-analyzer/xtask/src/codegen/grammar/ast_src.rs | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 10252ce6f3e49..620bba2d75c12 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -273,7 +273,7 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { !data.attrs.by_key(&sym::rustc_safe_intrinsic).exists() } else { // Extern items without `safe` modifier are always unsafe - !db.function_data(func).is_safe() + !data.is_safe() } } _ => false, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index cc0f4bfccc9a8..44be53b87ca5f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -554,7 +554,7 @@ fn main() { r#" //- /ed2021.rs crate:ed2021 edition:2021 #[rustc_deprecated_safe_2024] -unsafe fn safe_fn() -> u8 { +unsafe fn safe() -> u8 { 0 } //- /ed2024.rs crate:ed2024 edition:2024 @@ -564,7 +564,7 @@ unsafe fn not_safe() -> u8 { } //- /main.rs crate:main deps:ed2021,ed2024 fn main() { - ed2021::safe_fn(); + ed2021::safe(); ed2024::not_safe(); //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 5f46093da523e..c4dce0daa5b10 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -135,8 +135,8 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { has_mods = true; } - if p.at(T![safe]) { - p.eat(T![safe]); + if p.at_contextual_kw(T![safe]) { + p.eat_contextual_kw(T![safe]); has_mods = true; } diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 39d9d7e340b1c..8da338c0a2c50 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -94,7 +94,6 @@ pub enum SyntaxKind { PUB_KW, REF_KW, RETURN_KW, - SAFE_KW, SELF_KW, STATIC_KW, STRUCT_KW, @@ -137,6 +136,7 @@ pub enum SyntaxKind { PURE_KW, RAW_KW, READONLY_KW, + SAFE_KW, SYM_KW, TRY_KW, UNION_KW, @@ -365,7 +365,6 @@ impl SyntaxKind { | PUB_KW | REF_KW | RETURN_KW - | SAFE_KW | SELF_KW | STATIC_KW | STRUCT_KW @@ -418,6 +417,7 @@ impl SyntaxKind { PURE_KW => true, RAW_KW => true, READONLY_KW => true, + SAFE_KW => true, SYM_KW => true, UNION_KW => true, YEET_KW => true, @@ -460,7 +460,6 @@ impl SyntaxKind { | PUB_KW | REF_KW | RETURN_KW - | SAFE_KW | SELF_KW | STATIC_KW | STRUCT_KW @@ -506,6 +505,7 @@ impl SyntaxKind { PURE_KW => true, RAW_KW => true, READONLY_KW => true, + SAFE_KW => true, SYM_KW => true, UNION_KW => true, YEET_KW => true, @@ -617,7 +617,6 @@ impl SyntaxKind { "pub" => PUB_KW, "ref" => REF_KW, "return" => RETURN_KW, - "safe" => SAFE_KW, "self" => SELF_KW, "static" => STATIC_KW, "struct" => STRUCT_KW, @@ -668,6 +667,7 @@ impl SyntaxKind { "pure" => PURE_KW, "raw" => RAW_KW, "readonly" => READONLY_KW, + "safe" => SAFE_KW, "sym" => SYM_KW, "union" => UNION_KW, "yeet" => YEET_KW, @@ -711,4 +711,4 @@ impl SyntaxKind { } } #[macro_export] -macro_rules ! T { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } +macro_rules ! T { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs index f1a96e0c6a2d4..9269d15423534 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs @@ -111,7 +111,7 @@ const RESERVED: &[&str] = &[ // keywords that are keywords only in specific parse contexts #[doc(alias = "WEAK_KEYWORDS")] const CONTEXTUAL_KEYWORDS: &[&str] = - &["macro_rules", "union", "default", "raw", "dyn", "auto", "yeet"]; + &["macro_rules", "union", "default", "raw", "dyn", "auto", "yeet", "safe"]; // keywords we use for special macro expansions const CONTEXTUAL_BUILTIN_KEYWORDS: &[&str] = &[ "asm", From 4dd2af5113c975f865da460f166ea0809cf51c3b Mon Sep 17 00:00:00 2001 From: Daan Sieben Date: Mon, 21 Oct 2024 10:58:54 +0200 Subject: [PATCH 19/32] feat: support initializeStopped setting --- src/tools/rust-analyzer/editors/code/package.json | 5 +++++ src/tools/rust-analyzer/editors/code/src/config.ts | 4 ++++ src/tools/rust-analyzer/editors/code/src/main.ts | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 6c7f402dc5f93..8005527d2fa12 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -349,6 +349,11 @@ "markdownDescription": "Whether to show the test explorer.", "default": false, "type": "boolean" + }, + "rust-analyzer.initializeStopped": { + "markdownDescription": "Do not start rust-analyzer server when the extension is activated.", + "default": false, + "type": "boolean" } } }, diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index abb4099f9f5eb..67bc72f1e1268 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -330,6 +330,10 @@ export class Config { get statusBarClickAction() { return this.get("statusBar.clickAction"); } + + get initializeStopped() { + return this.get("initializeStopped"); + } } export function prepareVSCodeConfig(resp: T): T { diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 0ddc5619e9942..fdf43f66f9499 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -107,7 +107,14 @@ async function activateServer(ctx: Ctx): Promise { initializeDebugSessionTrackingAndRebuild(ctx); } - await ctx.start(); + if (ctx.config.initializeStopped) { + ctx.setServerStatus({ + health: "stopped", + }); + } else { + await ctx.start(); + } + return ctx; } From 657a9257106c2439ce8adb1ee4e933ace1763ed7 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 25 Aug 2024 00:32:25 +0200 Subject: [PATCH 20/32] Update rustc-hash to version 2 This brings in the new optimized algorithm that was shown to have small performance benefits for rustc. --- src/tools/rust-analyzer/Cargo.lock | 54 ++++++++++--------- src/tools/rust-analyzer/Cargo.toml | 2 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 7 +-- .../rust-analyzer/crates/ra-salsa/Cargo.toml | 2 +- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index da65d8804949a..951c7f8bbacc8 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -73,7 +73,7 @@ dependencies = [ "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lz4_flex", - "rustc-hash", + "rustc-hash 2.0.0", "salsa", "semver", "span", @@ -161,7 +161,7 @@ dependencies = [ "expect-test", "intern", "oorandom", - "rustc-hash", + "rustc-hash 2.0.0", "syntax", "syntax-bridge", "tt", @@ -216,7 +216,7 @@ dependencies = [ "chalk-derive", "chalk-ir", "chalk-solve", - "rustc-hash", + "rustc-hash 1.1.0", "tracing", ] @@ -232,7 +232,7 @@ dependencies = [ "indexmap", "itertools", "petgraph", - "rustc-hash", + "rustc-hash 1.1.0", "tracing", ] @@ -513,7 +513,7 @@ dependencies = [ "hir-ty", "intern", "itertools", - "rustc-hash", + "rustc-hash 2.0.0", "smallvec", "span", "stdx", @@ -547,7 +547,7 @@ dependencies = [ "mbe", "ra-ap-rustc_abi", "ra-ap-rustc_parse_format", - "rustc-hash", + "rustc-hash 2.0.0", "rustc_apfloat", "smallvec", "span", @@ -577,7 +577,7 @@ dependencies = [ "limit", "mbe", "parser", - "rustc-hash", + "rustc-hash 2.0.0", "smallvec", "span", "stdx", @@ -616,7 +616,7 @@ dependencies = [ "ra-ap-rustc_abi", "ra-ap-rustc_index", "ra-ap-rustc_pattern_analysis", - "rustc-hash", + "rustc-hash 2.0.0", "rustc_apfloat", "scoped-tls", "smallvec", @@ -737,7 +737,7 @@ dependencies = [ "parser", "profile", "rayon", - "rustc-hash", + "rustc-hash 2.0.0", "span", "stdx", "syntax", @@ -834,7 +834,7 @@ version = "0.0.0" dependencies = [ "dashmap", "hashbrown", - "rustc-hash", + "rustc-hash 2.0.0", "sptr", "triomphe", ] @@ -1051,7 +1051,7 @@ dependencies = [ "intern", "parser", "ra-ap-rustc_lexer", - "rustc-hash", + "rustc-hash 2.0.0", "smallvec", "span", "stdx", @@ -1345,7 +1345,7 @@ dependencies = [ "indexmap", "intern", "paths", - "rustc-hash", + "rustc-hash 2.0.0", "serde", "serde_json", "span", @@ -1435,7 +1435,7 @@ dependencies = [ "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", - "rustc-hash", + "rustc-hash 2.0.0", "semver", "serde", "serde_json", @@ -1555,7 +1555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "273d5f72926a58c7eea27aebc898d1d5b32d23d2342f692a94a2cf8746aa4a2f" dependencies = [ "ra-ap-rustc_index", - "rustc-hash", + "rustc-hash 1.1.0", "rustc_apfloat", "smallvec", "tracing", @@ -1640,7 +1640,7 @@ dependencies = [ "countme", "hashbrown", "memoffset", - "rustc-hash", + "rustc-hash 1.1.0", "text-size", ] @@ -1680,7 +1680,7 @@ dependencies = [ "profile", "project-model", "rayon", - "rustc-hash", + "rustc-hash 2.0.0", "scip", "semver", "serde", @@ -1717,6 +1717,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_apfloat" version = "0.2.1+llvm-462a31f5a5ab" @@ -1746,7 +1752,7 @@ dependencies = [ "oorandom", "parking_lot", "rand", - "rustc-hash", + "rustc-hash 2.0.0", "salsa-macros", "smallvec", "tracing", @@ -1898,7 +1904,7 @@ version = "0.0.0" dependencies = [ "hashbrown", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash", + "rustc-hash 2.0.0", "salsa", "stdx", "syntax", @@ -1967,7 +1973,7 @@ dependencies = [ "ra-ap-rustc_lexer", "rayon", "rowan", - "rustc-hash", + "rustc-hash 2.0.0", "rustc_apfloat", "smol_str", "stdx", @@ -1983,7 +1989,7 @@ version = "0.0.0" dependencies = [ "intern", "parser", - "rustc-hash", + "rustc-hash 2.0.0", "span", "stdx", "syntax", @@ -2000,7 +2006,7 @@ dependencies = [ "cfg", "hir-expand", "intern", - "rustc-hash", + "rustc-hash 2.0.0", "span", "stdx", "test-utils", @@ -2014,7 +2020,7 @@ dependencies = [ "dissimilar", "paths", "profile", - "rustc-hash", + "rustc-hash 2.0.0", "stdx", "text-size", "tracing", @@ -2361,7 +2367,7 @@ dependencies = [ "indexmap", "nohash-hasher", "paths", - "rustc-hash", + "rustc-hash 2.0.0", "stdx", "tracing", ] @@ -2374,7 +2380,7 @@ dependencies = [ "notify", "paths", "rayon", - "rustc-hash", + "rustc-hash 2.0.0", "stdx", "tracing", "vfs", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 17cefe941e57f..397c68319de46 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -136,7 +136,7 @@ process-wrap = { version = "8.0.2", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.0", default-features = false } rayon = "1.8.0" -rustc-hash = "1.1.0" +rustc-hash = "2.0.0" semver = "1.0.14" serde = { version = "1.0.192", features = ["derive"] } serde_json = "1.0.108" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 649cf88bb8da8..70e580eeae90a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -51,10 +51,7 @@ mod test_db; #[cfg(test)] mod tests; -use std::{ - collections::hash_map::Entry, - hash::{BuildHasherDefault, Hash}, -}; +use std::{collections::hash_map::Entry, hash::Hash}; use base_db::ra_salsa::InternValueTrivial; use chalk_ir::{ @@ -245,7 +242,7 @@ impl MemoryMap { match self { MemoryMap::Empty => Ok(Default::default()), MemoryMap::Simple(m) => transform((&0, m)).map(|(addr, val)| { - let mut map = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default()); + let mut map = FxHashMap::with_capacity_and_hasher(1, rustc_hash::FxBuildHasher); map.insert(addr, val); map }), diff --git a/src/tools/rust-analyzer/crates/ra-salsa/Cargo.toml b/src/tools/rust-analyzer/crates/ra-salsa/Cargo.toml index b81e780337fd1..f8a3156fe407a 100644 --- a/src/tools/rust-analyzer/crates/ra-salsa/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ra-salsa/Cargo.toml @@ -17,7 +17,7 @@ indexmap = "2.1.0" lock_api = "0.4" tracing = "0.1" parking_lot = "0.12.1" -rustc-hash = "1.0" +rustc-hash = "2.0.0" smallvec = "1.0.0" oorandom = "11" triomphe = "0.1.11" From bbaeeb82623d1a8503efa59cb0cb10537c8d9500 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Sep 2024 12:50:24 +0200 Subject: [PATCH 21/32] Fix recursive_adt fixture --- .../rust-analyzer/crates/hir-ty/src/consteval/tests.rs | 7 ++++--- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 7093fcadcb030..0a8bfaa70f86f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -95,7 +95,8 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); - let edition = db.crate_graph()[db.test_crate()].edition; + let edition = + db.crate_graph()[*db.crate_graph().crates_in_topological_order().last().unwrap()].edition; match e { ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition), ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition), @@ -2896,7 +2897,7 @@ fn recursive_adt() { { const VARIANT_TAG_TREE: TagTree = TagTree::Choice( &[ - TagTree::Leaf, + TAG_TREE, ], ); VARIANT_TAG_TREE @@ -2905,6 +2906,6 @@ fn recursive_adt() { TAG_TREE }; "#, - |e| matches!(e, ConstEvalError::MirEvalError(MirEvalError::StackOverflow)), + |e| matches!(e, ConstEvalError::MirLowerError(MirLowerError::Loop)), ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 70e580eeae90a..9c1d8bcf36f02 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -51,7 +51,7 @@ mod test_db; #[cfg(test)] mod tests; -use std::{collections::hash_map::Entry, hash::Hash}; +use std::hash::Hash; use base_db::ra_salsa::InternValueTrivial; use chalk_ir::{ @@ -62,10 +62,11 @@ use chalk_ir::{ use either::Either; use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId}; use hir_expand::name::Name; +use indexmap::{map::Entry, IndexMap}; use intern::{sym, Symbol}; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; use span::Edition; use syntax::ast::{make, ConstArg}; use traits::FnTrait; @@ -196,7 +197,7 @@ pub enum MemoryMap { #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct ComplexMemoryMap { - memory: FxHashMap>, + memory: IndexMap, FxBuildHasher>, vtable: VTableMap, } From e9da1dce058e9e2f9c66203f4b467e42aa4c45ad Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Sep 2024 13:22:37 +0200 Subject: [PATCH 22/32] Update ide tests --- .../ide-assists/src/handlers/bool_to_enum.rs | 3 +- .../crates/ide-completion/src/render.rs | 2 +- .../crates/ide/src/annotations.rs | 238 +++++++++--------- .../rust-analyzer/crates/ide/src/runnables.rs | 12 +- .../test_data/highlight_rainbow.html | 12 +- .../rust-analyzer/crates/mbe/src/benchmark.rs | 2 +- .../docs/user/generated_config.adoc | 44 ++-- .../rust-analyzer/editors/code/package.json | 44 ++-- 8 files changed, 179 insertions(+), 178 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index cd5fe0f86269c..c035c59ffca63 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -1095,6 +1095,7 @@ fn main() { #[test] fn field_enum_cross_file() { + // FIXME: The import is missing check_assist( bool_to_enum, r#" @@ -1132,7 +1133,7 @@ fn foo() { } //- /main.rs -use foo::{Bool, Foo}; +use foo::Foo; mod foo; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index f2e9de9382c6b..4dd171142f9c0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -1853,8 +1853,8 @@ fn f() { A { bar: b$0 }; } expect![[r#" fn bar() [type+name] fn baz() [type] - ex baz() [type] ex bar() [type] + ex baz() [type] st A [] fn f() [] "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs index 8e0166a4a76ca..121a463c9f155 100644 --- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs +++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs @@ -286,6 +286,20 @@ fn main() { ), }, }, + Annotation { + range: 53..57, + kind: HasReferences { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 53, + }, + data: Some( + [], + ), + }, + }, Annotation { range: 53..57, kind: Runnable( @@ -305,20 +319,6 @@ fn main() { }, ), }, - Annotation { - range: 53..57, - kind: HasReferences { - pos: FilePositionWrapper { - file_id: FileId( - 0, - ), - offset: 53, - }, - data: Some( - [], - ), - }, - }, ] "#]], ); @@ -336,6 +336,20 @@ fn main() { "#, expect![[r#" [ + Annotation { + range: 7..11, + kind: HasImpls { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [], + ), + }, + }, Annotation { range: 7..11, kind: HasReferences { @@ -358,13 +372,13 @@ fn main() { }, }, Annotation { - range: 7..11, - kind: HasImpls { + range: 17..21, + kind: HasReferences { pos: FilePositionWrapper { file_id: FileId( 0, ), - offset: 7, + offset: 17, }, data: Some( [], @@ -390,20 +404,6 @@ fn main() { }, ), }, - Annotation { - range: 17..21, - kind: HasReferences { - pos: FilePositionWrapper { - file_id: FileId( - 0, - ), - offset: 17, - }, - data: Some( - [], - ), - }, - }, ] "#]], ); @@ -427,7 +427,7 @@ fn main() { [ Annotation { range: 7..11, - kind: HasReferences { + kind: HasImpls { pos: FilePositionWrapper { file_id: FileId( 0, @@ -436,17 +436,14 @@ fn main() { }, data: Some( [ - FileRangeWrapper { - file_id: FileId( - 0, - ), - range: 57..61, - }, - FileRangeWrapper { + NavigationTarget { file_id: FileId( 0, ), - range: 93..97, + full_range: 36..64, + focus_range: 57..61, + name: "impl", + kind: Impl, }, ], ), @@ -454,7 +451,7 @@ fn main() { }, Annotation { range: 7..11, - kind: HasImpls { + kind: HasReferences { pos: FilePositionWrapper { file_id: FileId( 0, @@ -463,14 +460,17 @@ fn main() { }, data: Some( [ - NavigationTarget { + FileRangeWrapper { file_id: FileId( 0, ), - full_range: 36..64, - focus_range: 57..61, - name: "impl", - kind: Impl, + range: 57..61, + }, + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 93..97, }, ], ), @@ -521,20 +521,6 @@ fn main() { ), }, }, - Annotation { - range: 69..73, - kind: HasReferences { - pos: FilePositionWrapper { - file_id: FileId( - 0, - ), - offset: 69, - }, - data: Some( - [], - ), - }, - }, Annotation { range: 69..73, kind: Runnable( @@ -554,6 +540,20 @@ fn main() { }, ), }, + Annotation { + range: 69..73, + kind: HasReferences { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 69, + }, + data: Some( + [], + ), + }, + }, ] "#]], ); @@ -567,6 +567,20 @@ fn main() {} "#, expect![[r#" [ + Annotation { + range: 3..7, + kind: HasReferences { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 3, + }, + data: Some( + [], + ), + }, + }, Annotation { range: 3..7, kind: Runnable( @@ -586,20 +600,6 @@ fn main() {} }, ), }, - Annotation { - range: 3..7, - kind: HasReferences { - pos: FilePositionWrapper { - file_id: FileId( - 0, - ), - offset: 3, - }, - data: Some( - [], - ), - }, - }, ] "#]], ); @@ -623,7 +623,7 @@ fn main() { [ Annotation { range: 7..11, - kind: HasReferences { + kind: HasImpls { pos: FilePositionWrapper { file_id: FileId( 0, @@ -632,17 +632,14 @@ fn main() { }, data: Some( [ - FileRangeWrapper { - file_id: FileId( - 0, - ), - range: 19..23, - }, - FileRangeWrapper { + NavigationTarget { file_id: FileId( 0, ), - range: 74..78, + full_range: 14..56, + focus_range: 19..23, + name: "impl", + kind: Impl, }, ], ), @@ -650,7 +647,7 @@ fn main() { }, Annotation { range: 7..11, - kind: HasImpls { + kind: HasReferences { pos: FilePositionWrapper { file_id: FileId( 0, @@ -659,14 +656,17 @@ fn main() { }, data: Some( [ - NavigationTarget { + FileRangeWrapper { file_id: FileId( 0, ), - full_range: 14..56, - focus_range: 19..23, - name: "impl", - kind: Impl, + range: 19..23, + }, + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 74..78, }, ], ), @@ -693,20 +693,6 @@ fn main() { ), }, }, - Annotation { - range: 61..65, - kind: HasReferences { - pos: FilePositionWrapper { - file_id: FileId( - 0, - ), - offset: 61, - }, - data: Some( - [], - ), - }, - }, Annotation { range: 61..65, kind: Runnable( @@ -726,6 +712,20 @@ fn main() { }, ), }, + Annotation { + range: 61..65, + kind: HasReferences { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 61, + }, + data: Some( + [], + ), + }, + }, ] "#]], ); @@ -744,20 +744,6 @@ mod tests { "#, expect![[r#" [ - Annotation { - range: 3..7, - kind: HasReferences { - pos: FilePositionWrapper { - file_id: FileId( - 0, - ), - offset: 3, - }, - data: Some( - [], - ), - }, - }, Annotation { range: 3..7, kind: Runnable( @@ -777,6 +763,20 @@ mod tests { }, ), }, + Annotation { + range: 3..7, + kind: HasReferences { + pos: FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 3, + }, + data: Some( + [], + ), + }, + }, Annotation { range: 18..23, kind: Runnable( @@ -876,7 +876,7 @@ struct Foo; [ Annotation { range: 0..71, - kind: HasReferences { + kind: HasImpls { pos: FilePositionWrapper { file_id: FileId( 0, @@ -890,7 +890,7 @@ struct Foo; }, Annotation { range: 0..71, - kind: HasImpls { + kind: HasReferences { pos: FilePositionWrapper { file_id: FileId( 0, diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 38dc522789d71..3bbbd36c1b1a8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -1350,18 +1350,18 @@ mod tests { file_id: FileId( 0, ), - full_range: 121..185, - focus_range: 136..145, - name: "foo2_test", + full_range: 52..115, + focus_range: 67..75, + name: "foo_test", kind: Function, }, NavigationTarget { file_id: FileId( 0, ), - full_range: 52..115, - focus_range: 67..75, - name: "foo_test", + full_range: 121..185, + focus_range: 136..145, + name: "foo2_test", kind: Function, }, ] diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html index 5d51b1497895c..a4449b5d8d8e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html @@ -46,14 +46,14 @@ .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
fn main() {
-    let hello = "hello";
-    let x = hello.to_string();
-    let y = hello.to_string();
+    let hello = "hello";
+    let x = hello.to_string();
+    let y = hello.to_string();
 
-    let x = "other color please!";
-    let y = x.to_string();
+    let x = "other color please!";
+    let y = x.to_string();
 }
 
 fn bar() {
-    let mut hello = "hello";
+    let mut hello = "hello";
 }
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 9e4ef14074080..8ebdf1daa6c24 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -55,7 +55,7 @@ fn benchmark_expand_macro_rules() { }) .sum() }; - assert_eq!(hash, 69413); + assert_eq!(hash, 76353); } fn macro_rules_fixtures() -> FxHashMap { diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index babeb4272be62..463718835b91f 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -95,8 +95,8 @@ avoid checking unnecessary things. Default: ---- { - "debug_assertions": null, - "miri": null + "miri": null, + "debug_assertions": null } ---- List of cfg options to enable with the given values. @@ -321,18 +321,10 @@ Enables completions of private items and fields that are defined in the current Default: ---- { - "Arc::new": { - "postfix": "arc", - "body": "Arc::new(${receiver})", - "requires": "std::sync::Arc", - "description": "Put the expression into an `Arc`", - "scope": "expr" - }, - "Rc::new": { - "postfix": "rc", - "body": "Rc::new(${receiver})", - "requires": "std::rc::Rc", - "description": "Put the expression into an `Rc`", + "Ok": { + "postfix": "ok", + "body": "Ok(${receiver})", + "description": "Wrap the expression in a `Result::Ok`", "scope": "expr" }, "Box::pin": { @@ -342,10 +334,11 @@ Default: "description": "Put the expression into a pinned `Box`", "scope": "expr" }, - "Err": { - "postfix": "err", - "body": "Err(${receiver})", - "description": "Wrap the expression in a `Result::Err`", + "Arc::new": { + "postfix": "arc", + "body": "Arc::new(${receiver})", + "requires": "std::sync::Arc", + "description": "Put the expression into an `Arc`", "scope": "expr" }, "Some": { @@ -354,10 +347,17 @@ Default: "description": "Wrap the expression in an `Option::Some`", "scope": "expr" }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", + "Err": { + "postfix": "err", + "body": "Err(${receiver})", + "description": "Wrap the expression in a `Result::Err`", + "scope": "expr" + }, + "Rc::new": { + "postfix": "rc", + "body": "Rc::new(${receiver})", + "requires": "std::rc::Rc", + "description": "Put the expression into an `Rc`", "scope": "expr" } } diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 6c7f402dc5f93..70bb5f2447a21 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -728,8 +728,8 @@ "rust-analyzer.cargo.cfgs": { "markdownDescription": "List of cfg options to enable with the given values.", "default": { - "debug_assertions": null, - "miri": null + "miri": null, + "debug_assertions": null }, "type": "object" } @@ -1152,18 +1152,10 @@ "rust-analyzer.completion.snippets.custom": { "markdownDescription": "Custom completion snippets.", "default": { - "Arc::new": { - "postfix": "arc", - "body": "Arc::new(${receiver})", - "requires": "std::sync::Arc", - "description": "Put the expression into an `Arc`", - "scope": "expr" - }, - "Rc::new": { - "postfix": "rc", - "body": "Rc::new(${receiver})", - "requires": "std::rc::Rc", - "description": "Put the expression into an `Rc`", + "Ok": { + "postfix": "ok", + "body": "Ok(${receiver})", + "description": "Wrap the expression in a `Result::Ok`", "scope": "expr" }, "Box::pin": { @@ -1173,10 +1165,11 @@ "description": "Put the expression into a pinned `Box`", "scope": "expr" }, - "Err": { - "postfix": "err", - "body": "Err(${receiver})", - "description": "Wrap the expression in a `Result::Err`", + "Arc::new": { + "postfix": "arc", + "body": "Arc::new(${receiver})", + "requires": "std::sync::Arc", + "description": "Put the expression into an `Arc`", "scope": "expr" }, "Some": { @@ -1185,10 +1178,17 @@ "description": "Wrap the expression in an `Option::Some`", "scope": "expr" }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", + "Err": { + "postfix": "err", + "body": "Err(${receiver})", + "description": "Wrap the expression in a `Result::Err`", + "scope": "expr" + }, + "Rc::new": { + "postfix": "rc", + "body": "Rc::new(${receiver})", + "requires": "std::rc::Rc", + "description": "Put the expression into an `Rc`", "scope": "expr" } }, From 2adc6c33c9bb2a42a8d06ddcc719f2a2a7e56825 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 21 Oct 2024 11:34:19 +0200 Subject: [PATCH 23/32] fix: FIx mbe bench tests being iteration order dependent --- src/tools/rust-analyzer/crates/mbe/src/benchmark.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 8ebdf1daa6c24..270bc05a4ee2c 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -3,6 +3,7 @@ use intern::Symbol; use rustc_hash::FxHashMap; use span::{Edition, Span}; +use stdx::itertools::Itertools; use syntax::{ ast::{self, HasName}, AstNode, @@ -27,9 +28,10 @@ fn benchmark_parse_macro_rules() { let hash: usize = { let _pt = bench("mbe parse macro rules"); rules - .values() - .map(|it| { - DeclarativeMacro::parse_macro_rules(it, |_| span::Edition::CURRENT).rules.len() + .into_iter() + .sorted_by_key(|(id, _)| id.clone()) + .map(|(_, it)| { + DeclarativeMacro::parse_macro_rules(&it, |_| span::Edition::CURRENT).rules.len() }) .sum() }; @@ -55,12 +57,13 @@ fn benchmark_expand_macro_rules() { }) .sum() }; - assert_eq!(hash, 76353); + assert_eq!(hash, 65720); } fn macro_rules_fixtures() -> FxHashMap { macro_rules_fixtures_tt() .into_iter() + .sorted_by_key(|(id, _)| id.clone()) .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, |_| span::Edition::CURRENT))) .collect() } @@ -93,7 +96,7 @@ fn invocation_fixtures( let mut seed = 123456789; let mut res = Vec::new(); - for (name, it) in rules { + for (name, it) in rules.iter().sorted_by_key(|&(id, _)| id) { for rule in it.rules.iter() { // Generate twice for _ in 0..2 { From 8b4a94f261d77683684dbf4b9f4b1eac0dc5956a Mon Sep 17 00:00:00 2001 From: Khanh Duong Quoc Date: Sat, 19 Oct 2024 20:22:36 +0900 Subject: [PATCH 24/32] fix: private items are shown in completions for modules in fn body --- .../crates/hir-def/src/visibility.rs | 6 ++---- .../crates/ide-completion/src/tests/pattern.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 11d91513f1272..3aeb88047a0de 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -139,13 +139,11 @@ impl Visibility { let def_map_block = def_map.block_id(); loop { match (to_module.block, def_map_block) { - // to_module is not a block, so there is no parent def map to use + // `to_module` is not a block, so there is no parent def map to use. (None, _) => (), + // `to_module` is at `def_map`'s block, no need to move further. (Some(a), Some(b)) if a == b => { cov_mark::hit!(is_visible_from_same_block_def_map); - if let Some(parent) = def_map.parent() { - to_module = parent; - } } _ => { if let Some(parent) = to_module.def_map(db).parent() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index bd3e7c72bcd65..a5eb0369b1427 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -923,3 +923,21 @@ fn foo() { "#]], ); } + +#[test] +fn private_item_in_module_in_function_body() { + check_empty( + r#" +fn main() { + mod foo { + struct Private; + pub struct Public; + } + foo::$0 +} +"#, + expect![[r#" + st Public Public + "#]], + ); +} From e2dd95feb5b01caf030606cd50334b37fcc82250 Mon Sep 17 00:00:00 2001 From: roife Date: Mon, 21 Oct 2024 21:58:39 +0800 Subject: [PATCH 25/32] refactor add_keywords in ide-completions for clarity --- .../src/completions/item_list.rs | 103 ++++++++++-------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs index 1883377408332..83c994726a1e6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs @@ -75,73 +75,82 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None); let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait)); + let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock)); let in_trait = matches!(kind, Some(ItemListKind::Trait)); let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_))); let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); - let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); let in_block = kind.is_none(); - let missing_qualifiers = [ - ctx.qualifier_ctx.unsafe_tok.is_none().then_some(("unsafe", "unsafe $0")), - ctx.qualifier_ctx.async_tok.is_none().then_some(("async", "async $0")), - ]; - - if !in_trait_impl { - // handle qualifier tokens - if missing_qualifiers.iter().any(Option::is_none) { - // only complete missing qualifiers - missing_qualifiers.iter().filter_map(|x| *x).for_each(|(kw, snippet)| { - add_keyword(kw, snippet); - }); + let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); + let has_unsafe_kw = ctx.qualifier_ctx.unsafe_tok.is_some(); + let has_async_kw = ctx.qualifier_ctx.async_tok.is_some(); - if in_item_list || in_assoc_non_trait_impl { - add_keyword("fn", "fn $1($2) {\n $0\n}"); - } + // We handle completions for trait-impls in [`item_list::trait_impl`] + if in_trait_impl { + return; + } - if ctx.qualifier_ctx.unsafe_tok.is_some() && in_item_list { - add_keyword("trait", "trait $1 {\n $0\n}"); - if no_vis_qualifiers { - add_keyword("impl", "impl $1 {\n $0\n}"); - } - } + // Some keywords are invalid after non-vis qualifiers, so we handle them first. + if has_unsafe_kw || has_async_kw { + if !has_unsafe_kw { + add_keyword("unsafe", "unsafe $0"); + } + if !has_async_kw { + add_keyword("async", "async $0"); + } - return; + if in_item_list || in_assoc_non_trait_impl { + add_keyword("fn", "fn $1($2) {\n $0\n}"); } - if in_item_list { - add_keyword("enum", "enum $1 {\n $0\n}"); - add_keyword("mod", "mod $0"); - add_keyword("static", "static $0"); - add_keyword("struct", "struct $0"); + if has_unsafe_kw && in_item_list { add_keyword("trait", "trait $1 {\n $0\n}"); - add_keyword("union", "union $1 {\n $0\n}"); - add_keyword("use", "use $0"); if no_vis_qualifiers { add_keyword("impl", "impl $1 {\n $0\n}"); } } - if !in_trait && !in_block && no_vis_qualifiers { - add_keyword("pub(crate)", "pub(crate) $0"); - add_keyword("pub(super)", "pub(super) $0"); - add_keyword("pub", "pub $0"); + return; + } + + // ...and the rest deals with cases without any non-vis qualifiers. + + // Visibility qualifiers + if !in_trait && !in_block && no_vis_qualifiers { + add_keyword("pub(crate)", "pub(crate) $0"); + add_keyword("pub(super)", "pub(super) $0"); + add_keyword("pub", "pub $0"); + } + + // Keywords that are valid in `item_list` + if in_item_list { + add_keyword("enum", "enum $1 {\n $0\n}"); + add_keyword("mod", "mod $0"); + add_keyword("static", "static $0"); + add_keyword("struct", "struct $0"); + add_keyword("trait", "trait $1 {\n $0\n}"); + add_keyword("union", "union $1 {\n $0\n}"); + add_keyword("use", "use $0"); + if no_vis_qualifiers { + add_keyword("impl", "impl $1 {\n $0\n}"); } + } - if in_extern_block { - add_keyword("fn", "fn $1($2);"); - } else { - if !in_inherent_impl { - if !in_trait { - add_keyword("extern", "extern $0"); - } - add_keyword("type", "type $0"); + if in_extern_block { + add_keyword("fn", "fn $1($2);"); + add_keyword("static", "static $1: $2;"); + } else { + if !in_inherent_impl { + if !in_trait { + add_keyword("extern", "extern $0"); } - - add_keyword("fn", "fn $1($2) {\n $0\n}"); - add_keyword("unsafe", "unsafe $0"); - add_keyword("const", "const $0"); - add_keyword("async", "async $0"); + add_keyword("type", "type $0"); } + + add_keyword("fn", "fn $1($2) {\n $0\n}"); + add_keyword("unsafe", "unsafe $0"); + add_keyword("const", "const $0"); + add_keyword("async", "async $0"); } } From ba3b7c7961d3f08885b1734beb27f7fbd2d68246 Mon Sep 17 00:00:00 2001 From: roife Date: Mon, 21 Oct 2024 22:13:09 +0800 Subject: [PATCH 26/32] feat: better completions for extern blcoks --- .../src/completions/item_list.rs | 48 +++++++++++----- .../ide-completion/src/completions/keyword.rs | 1 + .../crates/ide-completion/src/context.rs | 8 ++- .../ide-completion/src/context/analysis.rs | 10 +++- .../ide-completion/src/tests/item_list.rs | 55 +++++++++++++++++++ 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs index 83c994726a1e6..2c4a880eb3343 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs @@ -76,7 +76,10 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let in_item_list = matches!(kind, Some(ItemListKind::SourceFile | ItemListKind::Module) | None); let in_assoc_non_trait_impl = matches!(kind, Some(ItemListKind::Impl | ItemListKind::Trait)); - let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock)); + let in_extern_block = matches!(kind, Some(ItemListKind::ExternBlock { .. })); + let in_unsafe_extern_block = + matches!(kind, Some(ItemListKind::ExternBlock { is_unsafe: true })); + let in_trait = matches!(kind, Some(ItemListKind::Trait)); let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_))); let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); @@ -85,6 +88,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); let has_unsafe_kw = ctx.qualifier_ctx.unsafe_tok.is_some(); let has_async_kw = ctx.qualifier_ctx.async_tok.is_some(); + let has_safe_kw = ctx.qualifier_ctx.safe_tok.is_some(); // We handle completions for trait-impls in [`item_list::trait_impl`] if in_trait_impl { @@ -92,22 +96,31 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option } // Some keywords are invalid after non-vis qualifiers, so we handle them first. - if has_unsafe_kw || has_async_kw { - if !has_unsafe_kw { - add_keyword("unsafe", "unsafe $0"); - } - if !has_async_kw { - add_keyword("async", "async $0"); - } + if has_unsafe_kw || has_async_kw || has_safe_kw { + if in_extern_block { + add_keyword("fn", "fn $1($2);"); + add_keyword("static", "static $1: $2;"); + } else { + if !has_unsafe_kw { + add_keyword("unsafe", "unsafe $0"); + } + if !has_async_kw { + add_keyword("async", "async $0"); + } - if in_item_list || in_assoc_non_trait_impl { - add_keyword("fn", "fn $1($2) {\n $0\n}"); - } + if in_item_list || in_assoc_non_trait_impl { + add_keyword("fn", "fn $1($2) {\n $0\n}"); + } - if has_unsafe_kw && in_item_list { - add_keyword("trait", "trait $1 {\n $0\n}"); - if no_vis_qualifiers { - add_keyword("impl", "impl $1 {\n $0\n}"); + if has_unsafe_kw && in_item_list { + add_keyword("trait", "trait $1 {\n $0\n}"); + if no_vis_qualifiers { + add_keyword("impl", "impl $1 {\n $0\n}"); + } + } + + if !has_async_kw && no_vis_qualifiers && in_item_list { + add_keyword("extern", "extern $0"); } } @@ -138,6 +151,11 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option } if in_extern_block { + add_keyword("unsafe", "unsafe $0"); + if in_unsafe_extern_block { + add_keyword("safe", "safe $0"); + } + add_keyword("fn", "fn $1($2);"); add_keyword("static", "static $1: $2;"); } else { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 0acb87872f5e3..71ca6e99494e6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -58,6 +58,7 @@ mod tests { r"fn my_fn() { unsafe $0 }", expect![[r#" kw async + kw extern kw fn kw impl kw trait diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index e49a9e3b0640e..0e1302ff2ef4e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -48,12 +48,16 @@ pub(crate) struct QualifierCtx { // TODO: Add try_tok and default_tok pub(crate) async_tok: Option, pub(crate) unsafe_tok: Option, + pub(crate) safe_tok: Option, pub(crate) vis_node: Option, } impl QualifierCtx { pub(crate) fn none(&self) -> bool { - self.async_tok.is_none() && self.unsafe_tok.is_none() && self.vis_node.is_none() + self.async_tok.is_none() + && self.unsafe_tok.is_none() + && self.safe_tok.is_none() + && self.vis_node.is_none() } } @@ -229,7 +233,7 @@ pub(crate) enum ItemListKind { Impl, TraitImpl(Option), Trait, - ExternBlock, + ExternBlock { is_unsafe: bool }, } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 1f9e3edf625d1..468ad81ad2f85 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1108,7 +1108,14 @@ fn classify_name_ref( }, None => return None, } }, - ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock }, + ast::ExternItemList(it) => { + let exn_blk = it.syntax().parent().and_then(ast::ExternBlock::cast); + PathKind::Item { + kind: ItemListKind::ExternBlock { + is_unsafe: exn_blk.and_then(|it| it.unsafe_token()).is_some(), + } + } + }, ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile }, _ => return None, } @@ -1310,6 +1317,7 @@ fn classify_name_ref( match token.kind() { SyntaxKind::UNSAFE_KW => qualifier_ctx.unsafe_tok = Some(token), SyntaxKind::ASYNC_KW => qualifier_ctx.async_tok = Some(token), + SyntaxKind::SAFE_KW => qualifier_ctx.safe_tok = Some(token), _ => {} } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs index 532d4928eff99..dfef8fa472ddf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs @@ -124,6 +124,7 @@ fn after_unsafe_token() { r#"unsafe $0"#, expect![[r#" kw async + kw extern kw fn kw impl kw trait @@ -495,3 +496,57 @@ type O = $0; ", ) } + +#[test] +fn inside_extern_blocks() { + // Should suggest `fn`, `static`, `unsafe` + check( + r#"extern { $0 }"#, + expect![[r#" + ma makro!(…) macro_rules! makro + md module + kw crate:: + kw fn + kw pub + kw pub(crate) + kw pub(super) + kw self:: + kw static + kw unsafe + "#]], + ); + + // Should suggest `fn`, `static`, `safe`, `unsafe` + check( + r#"unsafe extern { $0 }"#, + expect![[r#" + ma makro!(…) macro_rules! makro + md module + kw crate:: + kw fn + kw pub + kw pub(crate) + kw pub(super) + kw safe + kw self:: + kw static + kw unsafe + "#]], + ); + + check( + r#"unsafe extern { pub safe $0 }"#, + expect![[r#" + kw fn + kw static + "#]], + ); + + check( + r#"unsafe extern { pub unsafe $0 }"#, + expect![[r#" + kw fn + kw static + "#]], + ) +} From ea03a064110de6837f70e9795a9660991e588d03 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 21 Oct 2024 16:58:34 +0200 Subject: [PATCH 27/32] fix: Fix token downmapping failing for include! inputs --- .../crates/hir-expand/src/builtin/fn_macro.rs | 25 ++++----- .../rust-analyzer/crates/hir/src/semantics.rs | 52 +++++++++++-------- .../crates/hir/src/semantics/source_to_def.rs | 28 ++++++++-- .../crates/ide/src/goto_definition.rs | 38 ++++++++++++++ .../crates/ide/src/references.rs | 21 ++++++++ .../rust-analyzer/crates/syntax/src/ptr.rs | 2 +- 6 files changed, 125 insertions(+), 41 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index d04225b87227b..4894c7a93112b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -5,19 +5,20 @@ use cfg::CfgExpr; use either::Either; use intern::{sym, Symbol}; use mbe::{expect_fragment, DelimiterKind}; -use span::{Edition, EditionedFileId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; +use span::{Edition, EditionedFileId, Span}; use stdx::format_to; use syntax::{ format_smolstr, unescape::{unescape_byte, unescape_char, unescape_unicode, Mode}, }; -use syntax_bridge::parse_to_token_tree; +use syntax_bridge::syntax_node_to_token_tree; use crate::{ builtin::quote::{dollar_crate, quote}, db::ExpandDatabase, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, name, + span_map::SpanMap, tt::{self, DelimSpan}, ExpandError, ExpandResult, HirFileIdExt, Lookup as _, MacroCallId, }; @@ -739,18 +740,14 @@ fn include_expand( return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e) } }; - match parse_to_token_tree( - file_id.edition(), - SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, - SyntaxContextId::ROOT, - &db.file_text(file_id.file_id()), - ) { - Some(it) => ExpandResult::ok(it), - None => ExpandResult::new( - tt::Subtree::empty(DelimSpan { open: span, close: span }), - ExpandError::other(span, "failed to parse included file"), - ), - } + let span_map = db.real_span_map(file_id); + // FIXME: Parse errors + ExpandResult::ok(syntax_node_to_token_tree( + &db.parse(file_id).syntax_node(), + SpanMap::RealSpanMap(span_map), + span, + syntax_bridge::DocCommentDesugarMode::ProcMacro, + )) } pub fn include_input_to_file_id( diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index b27f1fbb5db13..3eac33ce99091 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -892,29 +892,8 @@ impl<'db> SemanticsImpl<'db> { f: &mut dyn FnMut(InFile, SyntaxContextId) -> ControlFlow, ) -> Option { let _p = tracing::info_span!("descend_into_macros_impl").entered(); - let (sa, span, file_id) = token - .parent() - .and_then(|parent| { - self.analyze_impl(InRealFile::new(file_id, &parent).into(), None, false) - }) - .and_then(|sa| { - let file_id = sa.file_id.file_id()?; - Some(( - sa, - self.db.real_span_map(file_id).span_for_range(token.text_range()), - HirFileId::from(file_id), - )) - })?; - let mut m_cache = self.macro_call_cache.borrow_mut(); - let def_map = sa.resolver.def_map(); - - // A stack of tokens to process, along with the file they came from - // These are tracked to know which macro calls we still have to look into - // the tokens themselves aren't that interesting as the span that is being used to map - // things down never changes. - let mut stack: Vec<(_, SmallVec<[_; 2]>)> = - vec![(file_id, smallvec![(token, SyntaxContextId::ROOT)])]; + let span = self.db.real_span_map(file_id).span_for_range(token.text_range()); // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { @@ -926,7 +905,6 @@ impl<'db> SemanticsImpl<'db> { .map(SmallVec::<[_; 2]>::from_iter), ) })?; - // we have found a mapping for the token if the vec is non-empty let res = mapped_tokens.is_empty().not().then_some(()); // requeue the tokens we got from mapping our current token down @@ -934,6 +912,33 @@ impl<'db> SemanticsImpl<'db> { res }; + // A stack of tokens to process, along with the file they came from + // These are tracked to know which macro calls we still have to look into + // the tokens themselves aren't that interesting as the span that is being used to map + // things down never changes. + let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![]; + let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id); + match include { + Some(include) => { + // include! inputs are always from real files, so they only need to be handled once upfront + process_expansion_for_token(&mut stack, include)?; + } + None => { + stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)])); + } + } + + let (file_id, tokens) = stack.first()?; + // make sure we pick the token in the expanded include if we encountered an include, + // otherwise we'll get the wrong semantics + let sa = + tokens.first()?.0.parent().and_then(|parent| { + self.analyze_impl(InFile::new(*file_id, &parent), None, false) + })?; + + let mut m_cache = self.macro_call_cache.borrow_mut(); + let def_map = sa.resolver.def_map(); + // Filters out all tokens that contain the given range (usually the macro call), any such // token is redundant as the corresponding macro call has already been processed let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| { @@ -1011,6 +1016,7 @@ impl<'db> SemanticsImpl<'db> { ) { call.as_macro_file() } else { + // FIXME: This is wrong, the SourceAnalyzer might be invalid here sa.expand(self.db, mcall.as_ref())? }; m_cache.insert(mcall, it); diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index fd6d52d6c9df2..389778b44ed9b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -104,7 +104,7 @@ use hir_expand::{ }; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{FileId, MacroFileId}; +use span::{EditionedFileId, FileId, MacroFileId}; use stdx::impl_from; use syntax::{ ast::{self, HasName}, @@ -118,9 +118,27 @@ pub(super) struct SourceToDefCache { pub(super) dynmap_cache: FxHashMap<(ChildContainer, HirFileId), DynMap>, expansion_info_cache: FxHashMap, pub(super) file_to_def_cache: FxHashMap>, + pub(super) included_file_cache: FxHashMap>, } impl SourceToDefCache { + pub(super) fn get_or_insert_include_for( + &mut self, + db: &dyn HirDatabase, + file: EditionedFileId, + ) -> Option { + if let Some(&m) = self.included_file_cache.get(&file) { + return m; + } + self.included_file_cache.insert(file, None); + for &crate_id in db.relevant_crates(file.into()).iter() { + db.include_macro_invoc(crate_id).iter().for_each(|&(macro_call_id, file_id)| { + self.included_file_cache.insert(file_id, Some(MacroFileId { macro_call_id })); + }); + } + self.included_file_cache.get(&file).copied().flatten() + } + pub(super) fn get_or_insert_expansion( &mut self, sema: &SemanticsImpl<'_>, @@ -163,9 +181,13 @@ impl SourceToDefCtx<'_, '_> { .include_macro_invoc(crate_id) .iter() .filter(|&&(_, file_id)| file_id == file) - .flat_map(|(call, _)| { + .flat_map(|&(macro_call_id, file_id)| { + self.cache + .included_file_cache + .insert(file_id, Some(MacroFileId { macro_call_id })); modules( - call.lookup(self.db.upcast()) + macro_call_id + .lookup(self.db.upcast()) .kind .file_id() .original_file(self.db.upcast()) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index c61b2ba84f2ef..4cbcb6ed050fd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -497,6 +497,44 @@ fn func_in_include() { //^^^^^^^^^^^^^^^ } +fn foo() { + func_in_include$0(); +} +"#, + ); + } + + #[test] + fn goto_def_in_included_file_inside_mod() { + check( + r#" +//- minicore:include +//- /main.rs +mod a { + include!("b.rs"); +} +//- /b.rs +fn func_in_include() { + //^^^^^^^^^^^^^^^ +} +fn foo() { + func_in_include$0(); +} +"#, + ); + + check( + r#" +//- minicore:include +//- /main.rs +mod a { + include!("a.rs"); +} +//- /a.rs +fn func_in_include() { + //^^^^^^^^^^^^^^^ +} + fn foo() { func_in_include$0(); } diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 64d717f88ddd9..e7cb8a253f405 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -2750,4 +2750,25 @@ impl Foo { "#]], ); } + + #[test] + fn goto_ref_on_included_file() { + check( + r#" +//- minicore:include +//- /lib.rs +include!("foo.rs"); +fn howdy() { + let _ = FOO; +} +//- /foo.rs +const FOO$0: i32 = 0; +"#, + expect![[r#" + FOO Const FileId(1) 0..19 6..9 + + FileId(0) 45..48 + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ptr.rs b/src/tools/rust-analyzer/crates/syntax/src/ptr.rs index ed4894f9b9c3c..11b79e4e0ed7b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ptr.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ptr.rs @@ -27,7 +27,7 @@ pub struct AstPtr { _ty: PhantomData N>, } -impl std::fmt::Debug for AstPtr { +impl std::fmt::Debug for AstPtr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("AstPtr").field(&self.raw).finish() } From ad27b8225f5ea209b6109a86f9972dad97611f7f Mon Sep 17 00:00:00 2001 From: roife Date: Tue, 22 Oct 2024 01:31:57 +0800 Subject: [PATCH 28/32] minor: refactor completions in item_list --- .../src/completions/item_list.rs | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs index 2c4a880eb3343..3ab341e4eded4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs @@ -29,7 +29,9 @@ pub(crate) fn complete_item_list( kind: &ItemListKind, ) { let _p = tracing::info_span!("complete_item_list").entered(); - if path_ctx.is_trivial_path() { + + // We handle completions for trait-impls in [`item_list::trait_impl`] + if path_ctx.is_trivial_path() && !matches!(kind, ItemListKind::TraitImpl(_)) { add_keywords(acc, ctx, Some(kind)); } @@ -81,7 +83,6 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option matches!(kind, Some(ItemListKind::ExternBlock { is_unsafe: true })); let in_trait = matches!(kind, Some(ItemListKind::Trait)); - let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_))); let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl)); let in_block = kind.is_none(); @@ -90,38 +91,34 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let has_async_kw = ctx.qualifier_ctx.async_tok.is_some(); let has_safe_kw = ctx.qualifier_ctx.safe_tok.is_some(); - // We handle completions for trait-impls in [`item_list::trait_impl`] - if in_trait_impl { + // Some keywords are invalid after non-vis qualifiers, so we handle them first. + if (has_unsafe_kw || has_safe_kw) && in_extern_block { + add_keyword("fn", "fn $1($2);"); + add_keyword("static", "static $1: $2;"); return; } - // Some keywords are invalid after non-vis qualifiers, so we handle them first. - if has_unsafe_kw || has_async_kw || has_safe_kw { - if in_extern_block { - add_keyword("fn", "fn $1($2);"); - add_keyword("static", "static $1: $2;"); - } else { - if !has_unsafe_kw { - add_keyword("unsafe", "unsafe $0"); - } - if !has_async_kw { - add_keyword("async", "async $0"); - } + if has_unsafe_kw || has_async_kw { + if !has_unsafe_kw { + add_keyword("unsafe", "unsafe $0"); + } + if !has_async_kw { + add_keyword("async", "async $0"); + } - if in_item_list || in_assoc_non_trait_impl { - add_keyword("fn", "fn $1($2) {\n $0\n}"); - } + if in_item_list || in_assoc_non_trait_impl { + add_keyword("fn", "fn $1($2) {\n $0\n}"); + } - if has_unsafe_kw && in_item_list { - add_keyword("trait", "trait $1 {\n $0\n}"); - if no_vis_qualifiers { - add_keyword("impl", "impl $1 {\n $0\n}"); - } + if has_unsafe_kw && in_item_list { + add_keyword("trait", "trait $1 {\n $0\n}"); + if no_vis_qualifiers { + add_keyword("impl", "impl $1 {\n $0\n}"); } + } - if !has_async_kw && no_vis_qualifiers && in_item_list { - add_keyword("extern", "extern $0"); - } + if !has_async_kw && no_vis_qualifiers && in_item_list { + add_keyword("extern", "extern $0"); } return; From 3952d493a7308e430678f7b32ccd848b0363ff76 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Tue, 22 Oct 2024 05:36:39 +0200 Subject: [PATCH 29/32] nuttx.md: typo --- src/doc/rustc/src/platform-support/nuttx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md index cbbede45f52f3..433a092aab22a 100644 --- a/src/doc/rustc/src/platform-support/nuttx.md +++ b/src/doc/rustc/src/platform-support/nuttx.md @@ -35,7 +35,7 @@ The following target names are defined: ## Building the target -The target can be built by enabled in the `rustc` build: +The target can be built by enabling it in the `rustc` build: ```toml [build] From 5038ee728227325ac0aca5e44c42171e473a93e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 22 Oct 2024 10:12:20 +0300 Subject: [PATCH 30/32] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index d0f9fa7ac4297..bc324402a96eb 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -dd5127615ad626741a1116d022cf784637ac05df +1de57a5ce952c722f7053aeacfc6c90bc139b678 From 420b665c60fe659ad05296fb6bd471ce6c724778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 22 Oct 2024 10:12:46 +0300 Subject: [PATCH 31/32] Bump rustc crates --- src/tools/rust-analyzer/Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 397c68319de46..9db62de9abfc0 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -85,11 +85,11 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.71.0", default-features = false } -ra-ap-rustc_parse_format = { version = "0.71.0", default-features = false } -ra-ap-rustc_index = { version = "0.71.0", default-features = false } -ra-ap-rustc_abi = { version = "0.71.0", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.71.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.73", default-features = false } +ra-ap-rustc_parse_format = { version = "0.73", default-features = false } +ra-ap-rustc_index = { version = "0.73", default-features = false } +ra-ap-rustc_abi = { version = "0.73", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.73", default-features = false } # local crates that aren't published to crates.io. These should not have versions. test-fixture = { path = "./crates/test-fixture" } From efc2ba2d902e979770a17e2da6e3d289d6909812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 22 Oct 2024 10:19:25 +0300 Subject: [PATCH 32/32] Replace some LayoutError variants with the rustc_abi errors --- src/tools/rust-analyzer/Cargo.lock | 26 +++++++++---------- .../rust-analyzer/crates/hir-ty/src/layout.rs | 20 +++++++------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 951c7f8bbacc8..fd569571b38bf 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1497,9 +1497,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.71.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6999d098000b98415939f13158dac78cb3eeeb7b0c073847f3e4b623866e27c" +checksum = "879ece0781e3c1cb670b9f29775c81a43a16db789d1296fad6bc5c74065b2fac" dependencies = [ "bitflags 2.6.0", "ra-ap-rustc_index", @@ -1508,9 +1508,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index" -version = "0.71.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9fb312d942817dab10790881f555928c1f6a11a85186e8e573ad4a86c7d3be" +checksum = "6910087ff89bb9f3db114bfcd86b5139042731fe7278d3ff4ceaa69a140154a7" dependencies = [ "arrayvec", "ra-ap-rustc_index_macros", @@ -1519,9 +1519,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.71.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "766e3990eb1066a06deefc561b5a01b32ca5c9211feea31cbf4ed50611519872" +checksum = "3b6f7bd12b678fbb37444ba77f3b0cfc13b7394a6dc7b0c799491fc9df0a9997" dependencies = [ "proc-macro2", "quote", @@ -1530,9 +1530,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.71.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4afa98eb7889c137d5a3f1cd189089e16da04d1e4837d358a67aa3dab10ffbe" +checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1" dependencies = [ "unicode-properties", "unicode-xid", @@ -1540,9 +1540,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.71.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9234c96ffb0565286790407fb7eb7f55ebf69267de4db382fdec0a17f14b0e2" +checksum = "70ed6150ae71d905c064dc88d7824ebb0fa81083f45d7477cba7b57176f2f635" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1550,12 +1550,12 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.71.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "273d5f72926a58c7eea27aebc898d1d5b32d23d2342f692a94a2cf8746aa4a2f" +checksum = "6e830862a0ec85fce211d34735315686bb8d6a12d418d6d735fb534aa1cd3293" dependencies = [ "ra-ap-rustc_index", - "rustc-hash 1.1.0", + "rustc-hash 2.0.0", "rustc_apfloat", "smallvec", "tracing", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 2c68d50013ead..80831440720cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -72,18 +72,15 @@ pub type Variants = hir_def::layout::Variants), - EmptyUnion, HasErrorConst, HasErrorType, HasPlaceholder, InvalidSimdType, NotImplemented, RecursiveTypeWithoutIndirection, - SizeOverflow, TargetLayoutNotAvailable, - UnexpectedUnsized, Unknown, UserReprTooSmall, } @@ -93,7 +90,6 @@ impl fmt::Display for LayoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { LayoutError::BadCalc(err) => err.fallback_fmt(f), - LayoutError::EmptyUnion => write!(f, "type is an union with no fields"), LayoutError::HasErrorConst => write!(f, "type contains an unevaluatable const"), LayoutError::HasErrorType => write!(f, "type contains an error"), LayoutError::HasPlaceholder => write!(f, "type contains placeholders"), @@ -102,11 +98,7 @@ impl fmt::Display for LayoutError { LayoutError::RecursiveTypeWithoutIndirection => { write!(f, "recursive type without indirection") } - LayoutError::SizeOverflow => write!(f, "size overflow"), LayoutError::TargetLayoutNotAvailable => write!(f, "target layout not available"), - LayoutError::UnexpectedUnsized => { - write!(f, "an unsized type was found where a sized type was expected") - } LayoutError::Unknown => write!(f, "unknown"), LayoutError::UserReprTooSmall => { write!(f, "the `#[repr]` hint is too small to hold the discriminants of the enum") @@ -181,7 +173,10 @@ fn layout_of_simd_ty( }; // Compute the size and alignment of the vector: - let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow)?; + let size = e_ly + .size + .checked_mul(e_len, dl) + .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; let align = dl.vector_align(size); let size = size.align_to(align.abi); @@ -294,7 +289,10 @@ pub fn layout_of_ty_query( TyKind::Array(element, count) => { let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64; let element = db.layout_of_ty(element.clone(), trait_env)?; - let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?; + let size = element + .size + .checked_mul(count, dl) + .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) { Abi::Uninhabited