Skip to content

Commit 2b461c5

Browse files
committed
Refine extraction targets of extract_function assist
1 parent 8d3b294 commit 2b461c5

File tree

3 files changed

+64
-64
lines changed

3 files changed

+64
-64
lines changed

crates/ide/src/rename.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -617,22 +617,22 @@ fn main() {
617617
#[test]
618618
fn test_rename_struct_field() {
619619
check(
620-
"j",
620+
"foo",
621621
r#"
622-
struct Foo { i$0: i32 }
622+
struct Foo { field$0: i32 }
623623
624624
impl Foo {
625625
fn new(i: i32) -> Self {
626-
Self { i: i }
626+
Self { field: i }
627627
}
628628
}
629629
"#,
630630
r#"
631-
struct Foo { j: i32 }
631+
struct Foo { foo: i32 }
632632
633633
impl Foo {
634634
fn new(i: i32) -> Self {
635-
Self { j: i }
635+
Self { foo: i }
636636
}
637637
}
638638
"#,
@@ -643,22 +643,22 @@ impl Foo {
643643
fn test_rename_field_in_field_shorthand() {
644644
cov_mark::check!(test_rename_field_in_field_shorthand);
645645
check(
646-
"j",
646+
"field",
647647
r#"
648-
struct Foo { i$0: i32 }
648+
struct Foo { foo$0: i32 }
649649
650650
impl Foo {
651-
fn new(i: i32) -> Self {
652-
Self { i }
651+
fn new(foo: i32) -> Self {
652+
Self { foo }
653653
}
654654
}
655655
"#,
656656
r#"
657-
struct Foo { j: i32 }
657+
struct Foo { field: i32 }
658658
659659
impl Foo {
660-
fn new(i: i32) -> Self {
661-
Self { j: i }
660+
fn new(foo: i32) -> Self {
661+
Self { field: foo }
662662
}
663663
}
664664
"#,

crates/ide_assists/src/handlers/extract_function.rs

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use syntax::{
1616
AstNode,
1717
},
1818
ted,
19-
SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR},
19+
SyntaxKind::{self, COMMENT},
2020
SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
2121
};
2222

@@ -466,22 +466,17 @@ enum FunctionBody {
466466
}
467467

468468
impl FunctionBody {
469-
fn from_whole_node(node: SyntaxNode) -> Option<Self> {
470-
match node.kind() {
471-
PATH_EXPR => None,
472-
BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()).map(Self::Expr),
473-
RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()).map(Self::Expr),
474-
BLOCK_EXPR => ast::BlockExpr::cast(node)
475-
.filter(|it| it.is_standalone())
476-
.map(Into::into)
477-
.map(Self::Expr),
478-
_ => ast::Expr::cast(node).map(Self::Expr),
469+
fn from_expr(expr: ast::Expr) -> Option<Self> {
470+
match expr {
471+
ast::Expr::BreakExpr(it) => it.expr().map(Self::Expr),
472+
ast::Expr::ReturnExpr(it) => it.expr().map(Self::Expr),
473+
ast::Expr::BlockExpr(it) if !it.is_standalone() => None,
474+
expr => Some(Self::Expr(expr)),
479475
}
480476
}
481477

482-
fn from_range(node: SyntaxNode, text_range: TextRange) -> Option<FunctionBody> {
483-
let block = ast::BlockExpr::cast(node)?;
484-
Some(Self::Span { parent: block, text_range })
478+
fn from_range(parent: ast::BlockExpr, text_range: TextRange) -> FunctionBody {
479+
Self::Span { parent, text_range }
485480
}
486481

487482
fn indent_level(&self) -> IndentLevel {
@@ -592,44 +587,39 @@ struct OutlivedLocal {
592587
/// ```
593588
///
594589
fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<FunctionBody> {
595-
// we have selected exactly the expr node
596-
// wrap it before anything else
597-
if node.text_range() == selection_range {
598-
let body = FunctionBody::from_whole_node(node.clone());
599-
if body.is_some() {
600-
return body;
601-
}
590+
if let Some(stmt) = ast::Stmt::cast(node.clone()) {
591+
return match stmt {
592+
ast::Stmt::Item(_) => None,
593+
ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => Some(FunctionBody::from_range(
594+
node.parent().and_then(ast::BlockExpr::cast)?,
595+
node.text_range(),
596+
)),
597+
};
602598
}
603599

604-
// we have selected a few statements in a block
605-
// so covering_element returns the whole block
606-
if node.kind() == BLOCK_EXPR {
607-
// Extract the full statements.
608-
let statements_range = node
609-
.children()
610-
.filter(|c| selection_range.intersect(c.text_range()).is_some())
611-
.fold(selection_range, |acc, c| acc.cover(c.text_range()));
612-
let body = FunctionBody::from_range(node.clone(), statements_range);
613-
if body.is_some() {
614-
return body;
615-
}
600+
let expr = ast::Expr::cast(node.clone())?;
601+
// A node got selected fully
602+
if node.text_range() == selection_range {
603+
return FunctionBody::from_expr(expr.clone());
616604
}
617605

618-
// we have selected single statement
619-
// `from_whole_node` failed because (let) statement is not and expression
620-
// so we try to expand covering_element to parent and repeat the previous
621-
if let Some(parent) = node.parent() {
622-
if parent.kind() == BLOCK_EXPR {
623-
// Extract the full statement.
624-
let body = FunctionBody::from_range(parent, node.text_range());
625-
if body.is_some() {
626-
return body;
627-
}
606+
// Covering element returned the parent block of one or multiple statements that have been selected
607+
if let ast::Expr::BlockExpr(block) = expr {
608+
// Extract the full statements.
609+
let mut statements_range = block
610+
.statements()
611+
.filter(|stmt| selection_range.intersect(stmt.syntax().text_range()).is_some())
612+
.fold(selection_range, |acc, stmt| acc.cover(stmt.syntax().text_range()));
613+
if let Some(e) = block
614+
.tail_expr()
615+
.filter(|it| selection_range.intersect(it.syntax().text_range()).is_some())
616+
{
617+
statements_range = statements_range.cover(e.syntax().text_range());
628618
}
619+
return Some(FunctionBody::from_range(block, statements_range));
629620
}
630621

631-
// select the closest containing expr (both ifs are used)
632-
std::iter::once(node.clone()).chain(node.ancestors()).find_map(FunctionBody::from_whole_node)
622+
node.ancestors().find_map(ast::Expr::cast).and_then(FunctionBody::from_expr)
633623
}
634624

635625
/// list local variables that are referenced in `body`
@@ -3743,6 +3733,16 @@ async fn $0fun_name() {
37433733
async fn some_function() {
37443734
37453735
}
3736+
"#,
3737+
);
3738+
}
3739+
3740+
#[test]
3741+
fn extract_does_not_extract_standalone_blocks() {
3742+
check_assist_not_applicable(
3743+
extract_function,
3744+
r#"
3745+
fn main() $0{}$0
37463746
"#,
37473747
);
37483748
}

crates/ide_db/src/rename.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ fn rename_reference(
229229
let ident_kind = IdentifierKind::classify(new_name)?;
230230

231231
if matches!(
232-
def, // is target a lifetime?
232+
def,
233233
Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_)
234234
) {
235235
match ident_kind {
@@ -240,13 +240,13 @@ fn rename_reference(
240240
IdentifierKind::Lifetime => cov_mark::hit!(rename_lifetime),
241241
}
242242
} else {
243-
match (ident_kind, def) {
244-
(IdentifierKind::Lifetime, _) => {
243+
match ident_kind {
244+
IdentifierKind::Lifetime => {
245245
cov_mark::hit!(rename_not_an_ident_ref);
246246
bail!("Invalid name `{}`: not an identifier", new_name);
247247
}
248-
(IdentifierKind::Ident, _) => cov_mark::hit!(rename_non_local),
249-
(IdentifierKind::Underscore, _) => (),
248+
IdentifierKind::Ident => cov_mark::hit!(rename_non_local),
249+
IdentifierKind::Underscore => (),
250250
}
251251
}
252252

@@ -325,6 +325,8 @@ pub fn source_edit_from_references(
325325

326326
fn source_edit_from_name(name: &ast::Name, new_name: &str) -> Option<(TextRange, String)> {
327327
if let Some(_) = ast::RecordPatField::for_field_name(name) {
328+
// FIXME: instead of splitting the shorthand, recursively trigger a rename of the
329+
// other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
328330
if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
329331
return Some((
330332
TextRange::empty(ident_pat.syntax().text_range().start()),
@@ -368,8 +370,6 @@ fn source_edit_from_name_ref(
368370
None
369371
}
370372
// init shorthand
371-
// FIXME: instead of splitting the shorthand, recursively trigger a rename of the
372-
// other name https://github.com/rust-analyzer/rust-analyzer/issues/6547
373373
(None, Some(_)) if matches!(def, Definition::Field(_)) => {
374374
cov_mark::hit!(test_rename_field_in_field_shorthand);
375375
let s = name_ref.syntax().text_range().start();

0 commit comments

Comments
 (0)