Skip to content

Commit 1edbaa2

Browse files
committed
Wrap inner tail expressions in MissingOkOrSomeInTailExpr
1 parent eb513c2 commit 1edbaa2

File tree

8 files changed

+69
-11
lines changed

8 files changed

+69
-11
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use hir_def::path::ModPath;
99
use hir_expand::{name::Name, HirFileId, InFile};
1010
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
1111

12+
use crate::Type;
13+
1214
macro_rules! diagnostics {
1315
($($diag:ident,)*) => {
1416
pub enum AnyDiagnostic {$(
@@ -142,6 +144,7 @@ pub struct MissingOkOrSomeInTailExpr {
142144
pub expr: InFile<AstPtr<ast::Expr>>,
143145
// `Some` or `Ok` depending on whether the return type is Result or Option
144146
pub required: String,
147+
pub expected: Type,
145148
}
146149

147150
#[derive(Debug)]

crates/hir/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1216,7 +1216,14 @@ impl Function {
12161216
}
12171217
BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => {
12181218
match source_map.expr_syntax(expr) {
1219-
Ok(expr) => acc.push(MissingOkOrSomeInTailExpr { expr, required }.into()),
1219+
Ok(expr) => acc.push(
1220+
MissingOkOrSomeInTailExpr {
1221+
expr,
1222+
required,
1223+
expected: self.ret_type(db),
1224+
}
1225+
.into(),
1226+
),
12201227
Err(SyntheticSyntax) => (),
12211228
}
12221229
}

crates/hir_ty/src/diagnostics/match_check.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
88
mod deconstruct_pat;
99
mod pat_util;
10+
1011
pub(crate) mod usefulness;
1112

1213
use hir_def::{body::Body, EnumVariantId, LocalFieldId, VariantId};

crates/ide/src/highlight_related.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ fn foo() ->$0 u32 {
533533
5
534534
// ^
535535
}
536+
} else if false {
537+
0
538+
// ^
536539
} else {
537540
match 5 {
538541
6 => 100,

crates/ide_completion/src/context.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -624,11 +624,7 @@ impl<'a> CompletionContext<'a> {
624624
fn classify_name(&mut self, name: ast::Name) {
625625
if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
626626
self.is_pat_or_const = Some(PatternRefutability::Refutable);
627-
// if any of these is here our bind pat can't be a const pat anymore
628-
let complex_ident_pat = bind_pat.at_token().is_some()
629-
|| bind_pat.ref_token().is_some()
630-
|| bind_pat.mut_token().is_some();
631-
if complex_ident_pat {
627+
if !bind_pat.is_simple_ident() {
632628
self.is_pat_or_const = None;
633629
} else {
634630
let irrefutable_pat = bind_pat.syntax().ancestors().find_map(|node| {

crates/ide_db/src/helpers.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,20 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
271271
ast::Effect::Async(_) | ast::Effect::Try(_) | ast::Effect::Const(_) => cb(expr),
272272
},
273273
ast::Expr::IfExpr(if_) => {
274-
if_.blocks().for_each(|block| for_each_tail_expr(&ast::Expr::BlockExpr(block), cb))
274+
let mut if_ = if_.clone();
275+
loop {
276+
if let Some(block) = if_.then_branch() {
277+
for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
278+
}
279+
match if_.else_branch() {
280+
Some(ast::ElseBranch::IfExpr(it)) => if_ = it,
281+
Some(ast::ElseBranch::Block(block)) => {
282+
for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
283+
break;
284+
}
285+
None => break,
286+
}
287+
}
275288
}
276289
ast::Expr::LoopExpr(l) => {
277290
for_each_break_expr(l.label(), l.loop_body(), &mut |b| cb(&ast::Expr::BreakExpr(b)))

crates/ide_diagnostics/src/handlers/missing_ok_or_some_in_tail_expr.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use hir::db::AstDatabase;
2-
use ide_db::{assists::Assist, source_change::SourceChange};
2+
use ide_db::{assists::Assist, helpers::for_each_tail_expr, source_change::SourceChange};
33
use syntax::AstNode;
44
use text_edit::TextEdit;
55

@@ -33,10 +33,15 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingOkOrSomeInTailExpr) -> Op
3333
let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
3434
let tail_expr = d.expr.value.to_node(&root);
3535
let tail_expr_range = tail_expr.syntax().text_range();
36-
let replacement = format!("{}({})", d.required, tail_expr.syntax());
37-
let edit = TextEdit::replace(tail_expr_range, replacement);
36+
let mut builder = TextEdit::builder();
37+
for_each_tail_expr(&tail_expr, &mut |expr| {
38+
if ctx.sema.type_of_expr(expr).as_ref() != Some(&d.expected) {
39+
builder.insert(expr.syntax().text_range().start(), format!("{}(", d.required));
40+
builder.insert(expr.syntax().text_range().end(), ")".to_string());
41+
}
42+
});
3843
let source_change =
39-
SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit);
44+
SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
4045
let name = if d.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
4146
Some(vec![fix("wrap_tail_expr", name, source_change, tail_expr_range)])
4247
}
@@ -68,6 +73,35 @@ fn div(x: i32, y: i32) -> Option<i32> {
6873
);
6974
}
7075

76+
#[test]
77+
fn test_wrap_return_type_option_tails() {
78+
check_fix(
79+
r#"
80+
//- minicore: option, result
81+
fn div(x: i32, y: i32) -> Option<i32> {
82+
if y == 0 {
83+
0
84+
} else if true {
85+
100
86+
} else {
87+
None
88+
}$0
89+
}
90+
"#,
91+
r#"
92+
fn div(x: i32, y: i32) -> Option<i32> {
93+
if y == 0 {
94+
Some(0)
95+
} else if true {
96+
Some(100)
97+
} else {
98+
None
99+
}
100+
}
101+
"#,
102+
);
103+
}
104+
71105
#[test]
72106
fn test_wrap_return_type() {
73107
check_fix(

crates/syntax/src/ast/expr_ext.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ impl ast::IfExpr {
164164
pub fn then_branch(&self) -> Option<ast::BlockExpr> {
165165
self.blocks().next()
166166
}
167+
167168
pub fn else_branch(&self) -> Option<ElseBranch> {
168169
let res = match self.blocks().nth(1) {
169170
Some(block) => ElseBranch::Block(block),

0 commit comments

Comments
 (0)