252: Improve 'introduce variable' r=matklad a=flodiebold

 - make it possible to extract a prefix of an expression statement (e.g.
   `<|>foo.bar()<|>.baz()`)
 - don't turn the last expression in a block into a let statement
 - also fix a few typos

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2018-12-02 13:08:16 +00:00
commit 0bdf8deb77
2 changed files with 44 additions and 7 deletions

View file

@ -122,7 +122,7 @@ pub fn introduce_variable<'a>(
let node = find_covering_node(file.syntax(), range); let node = find_covering_node(file.syntax(), range);
let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;
let anchor_stmt = ahchor_stmt(expr)?; let anchor_stmt = anchor_stmt(expr)?;
let indent = anchor_stmt.prev_sibling()?; let indent = anchor_stmt.prev_sibling()?;
if indent.kind() != WHITESPACE { if indent.kind() != WHITESPACE {
return None; return None;
@ -133,7 +133,12 @@ pub fn introduce_variable<'a>(
buf.push_str("let var_name = "); buf.push_str("let var_name = ");
expr.syntax().text().push_to(&mut buf); expr.syntax().text().push_to(&mut buf);
if expr.syntax().range().start() == anchor_stmt.range().start() { let is_full_stmt = if let Some(expr_stmt) = ast::ExprStmt::cast(anchor_stmt) {
Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
} else {
false
};
if is_full_stmt {
edit.replace(expr.syntax().range(), buf); edit.replace(expr.syntax().range(), buf);
} else { } else {
buf.push_str(";"); buf.push_str(";");
@ -150,7 +155,7 @@ pub fn introduce_variable<'a>(
/// Statement or last in the block expression, which will follow /// Statement or last in the block expression, which will follow
/// the freshly introduced var. /// the freshly introduced var.
fn ahchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> { fn anchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> {
expr.syntax().ancestors().find(|&node| { expr.syntax().ancestors().find(|&node| {
if ast::Stmt::cast(node).is_some() { if ast::Stmt::cast(node).is_some() {
return true; return true;
@ -250,7 +255,7 @@ struct Foo { a: i32, }
} }
#[test] #[test]
fn test_intrdoduce_var_simple() { fn test_introduce_var_simple() {
check_action_range( check_action_range(
" "
fn foo() { fn foo() {
@ -266,7 +271,7 @@ fn foo() {
} }
#[test] #[test]
fn test_intrdoduce_var_expr_stmt() { fn test_introduce_var_expr_stmt() {
check_action_range( check_action_range(
" "
fn foo() { fn foo() {
@ -281,7 +286,23 @@ fn foo() {
} }
#[test] #[test]
fn test_intrdoduce_var_last_expr() { fn test_introduce_var_part_of_expr_stmt() {
check_action_range(
"
fn foo() {
<|>1<|> + 1;
}",
"
fn foo() {
let <|>var_name = 1;
var_name + 1;
}",
|file, range| introduce_variable(file, range).map(|f| f()),
);
}
#[test]
fn test_introduce_var_last_expr() {
check_action_range( check_action_range(
" "
fn foo() { fn foo() {
@ -296,4 +317,20 @@ fn foo() {
); );
} }
#[test]
fn test_introduce_var_last_full_expr() {
check_action_range(
"
fn foo() {
<|>bar(1 + 1)<|>
}",
"
fn foo() {
let <|>var_name = bar(1 + 1);
var_name
}",
|file, range| introduce_variable(file, range).map(|f| f()),
);
}
} }

View file

@ -26,7 +26,7 @@ impl EditBuilder {
} }
pub fn finish(self) -> Edit { pub fn finish(self) -> Edit {
let mut atoms = self.atoms; let mut atoms = self.atoms;
atoms.sort_by_key(|a| a.delete.start()); atoms.sort_by_key(|a| (a.delete.start(), a.delete.end()));
for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) {
assert!(a1.delete.end() <= a2.delete.start()) assert!(a1.delete.end() <= a2.delete.start())
} }