Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion crates/ide-assists/src/handlers/extract_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,17 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr {
/// Check whether the node is a valid expression which can be extracted to a variable.
/// In general that's true for any expression, but in some cases that would produce invalid code.
fn valid_target_expr(ctx: &AssistContext<'_>) -> impl Fn(SyntaxNode) -> Option<ast::Expr> {
|node| match node.kind() {
let selection = ctx.selection_trimmed();
move |node| match node.kind() {
SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None,
SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
SyntaxKind::BLOCK_EXPR => {
ast::BlockExpr::cast(node).filter(|it| it.is_standalone()).map(ast::Expr::from)
}
SyntaxKind::ARG_LIST => ast::ArgList::cast(node)?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also pass when multiple args are selected. Also ARG_LIST isn't the only place for things like that (e.g. ARRAY_EXPR is too). IMO we should disable the assist when the comma is selected, but I also agree to enable it if it's confined to where only a single item is selected.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should disable the assist when the comma is selected

When multiple parameters are selected, the old behavior will also pass, and I don't think this will break some habits

Copy link
Copy Markdown
Member Author

@A4-Tacks A4-Tacks Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. ARRAY_EXPR is too

No, ARRAY_EXPR is quite normal. Its behavior is to extract the entire array

Need to determine if the selected single expression should be an array, not an arglist?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When multiple parameters are selected, the old behavior will also pass, and I don't think this will break some habits

True, but it's still incorrect.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems difficult, if multiple args are selected in arglist and valid_target_expr returns None, it will degenerate into its original behavior because valid_target_expr is applied to node.descendants()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine then.

.args()
.find(|expr| crate::utils::is_selected(expr, selection, false)),
SyntaxKind::PATH_EXPR => {
let path_expr = ast::PathExpr::cast(node)?;
let path_resolution = ctx.sema.resolve_path(&path_expr.path()?)?;
Expand Down Expand Up @@ -1285,6 +1289,33 @@ fn main() {
);
}

#[test]
fn extract_var_in_arglist_with_comma() {
check_assist_by_label(
extract_variable,
r#"
fn main() {
let x = 2;
foo(
x + x,
$0x - x,$0
)
}
"#,
r#"
fn main() {
let x = 2;
let $0var_name = x - x;
foo(
x + x,
var_name,
)
}
"#,
"Extract into variable",
);
}

#[test]
fn extract_var_path_simple() {
check_assist_by_label(
Expand Down