mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
ssr: Allow replacing expressions with statements
Now that statements can be matched and replaced (#6587) some usecases require expressions to be replaced with statements as well. This happens when something that can ambiguously be an expression or statement like `if` and loop blocks appear in the last position of a block, as trailing expression. In this case a replacement pattern of the form `if foo(){$a();}==>>$a();` will only substitute `if` blocks in the list of statements but not if they (implicitly) end up in the trailing expression, where they are not wrapped by an EXPR_STMT (but the pattern and template are, as parsing only succeeds for the `stmt ==>> stmt` case). Instead of adding two rules that match an expression - and emit duplicate matching errors - allow the template for expressions to be a statement if it fails to parse as an expression.
This commit is contained in:
parent
b87699d97a
commit
d33edb4e9c
2 changed files with 60 additions and 3 deletions
|
@ -73,12 +73,18 @@ impl ParsedRule {
|
|||
placeholders_by_stand_in: pattern.placeholders_by_stand_in(),
|
||||
rules: Vec::new(),
|
||||
};
|
||||
builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse));
|
||||
|
||||
let raw_template_stmt = raw_template.map(ast::Stmt::parse);
|
||||
if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) {
|
||||
builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr);
|
||||
} else {
|
||||
builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone());
|
||||
}
|
||||
builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse));
|
||||
builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse));
|
||||
builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse));
|
||||
builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse));
|
||||
builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template.map(ast::Stmt::parse));
|
||||
builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt);
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +95,11 @@ struct RuleBuilder {
|
|||
}
|
||||
|
||||
impl RuleBuilder {
|
||||
fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) {
|
||||
fn try_add<T: AstNode, T2: AstNode>(
|
||||
&mut self,
|
||||
pattern: Result<T, ()>,
|
||||
template: Option<Result<T2, ()>>,
|
||||
) {
|
||||
match (pattern, template) {
|
||||
(Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {
|
||||
placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
|
||||
|
|
|
@ -203,6 +203,53 @@ fn ssr_let_stmt_replace_expr() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssr_blockexpr_replace_stmt_with_stmt() {
|
||||
assert_ssr_transform(
|
||||
"if $a() {$b;} ==>> $b;",
|
||||
"{
|
||||
if foo() {
|
||||
bar();
|
||||
}
|
||||
Ok(())
|
||||
}",
|
||||
expect![[r#"{
|
||||
bar();
|
||||
Ok(())
|
||||
}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssr_blockexpr_match_trailing_expr() {
|
||||
assert_matches(
|
||||
"if $a() {$b;}",
|
||||
"{
|
||||
if foo() {
|
||||
bar();
|
||||
}
|
||||
}",
|
||||
&["if foo() {
|
||||
bar();
|
||||
}"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssr_blockexpr_replace_trailing_expr_with_stmt() {
|
||||
assert_ssr_transform(
|
||||
"if $a() {$b;} ==>> $b;",
|
||||
"{
|
||||
if foo() {
|
||||
bar();
|
||||
}
|
||||
}",
|
||||
expect![["{
|
||||
bar();
|
||||
}"]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssr_function_to_method() {
|
||||
assert_ssr_transform(
|
||||
|
|
Loading…
Reference in a new issue