Skip to content

Commit 6592c74

Browse files
committed
fix: offer 'type_mismatch' some fixes inside macro
- Supports macro for `add_missing_ok_or_some` and `str_ref_to_owned` Example --- ```rust macro_rules! identity { ($($t:tt)*) => ($($t)*) } identity! { fn test() -> String { "a"$0 } } ``` **Before this PR** Invalid trigger range and edit range **After this PR** ```rust macro_rules! identity { ($($t:tt)*) => ($($t)*) } identity! { fn test() -> String { "a".to_owned() } } ``` --- ```rust macro_rules! identity { ($($t:tt)*) => ($($t)*) } identity! { fn div(x: i32, y: i32) -> Result<i32, ()> { if y == 0 { return Err(()); } x / y$0 } } ``` **Before this PR** Invalid trigger range and edit range **After this PR** ```rust macro_rules! identity { ($($t:tt)*) => ($($t)*) } identity! { fn div(x: i32, y: i32) -> Result<i32, ()> { if y == 0 { return Err(()); } Ok(x / y) } } ```
1 parent 5f147cc commit 6592c74

1 file changed

Lines changed: 61 additions & 14 deletions

File tree

crates/ide-diagnostics/src/handlers/type_mismatch.rs

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ fn add_missing_ok_or_some(
101101
) -> Option<()> {
102102
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
103103
let expr = expr_ptr.value.to_node(&root);
104-
let expr_range = expr.syntax().text_range();
104+
let expr_range = ctx.sema.original_range_opt(expr.syntax())?.range;
105105
let scope = ctx.sema.scope(expr.syntax())?;
106106

107107
let expected_adt = d.expected.as_adt()?;
@@ -135,13 +135,13 @@ fn add_missing_ok_or_some(
135135
// Empty block
136136
let indent = block_indent + 1;
137137
builder.insert(
138-
block.syntax().text_range().start() + TextSize::from(1),
138+
expr_range.start() + TextSize::from(1),
139139
format!("\n{indent}{variant_name}(())\n{block_indent}"),
140140
);
141141
} else {
142142
let indent = IndentLevel::from(1);
143143
builder.insert(
144-
block.syntax().text_range().end() - TextSize::from(1),
144+
expr_range.end() - TextSize::from(1),
145145
format!("{indent}{variant_name}(())\n{block_indent}"),
146146
);
147147
}
@@ -158,8 +158,7 @@ fn add_missing_ok_or_some(
158158
// Fix for forms like `fn foo() -> Result<(), String> { return; }`
159159
if ret_expr.expr().is_none() {
160160
let mut builder = TextEdit::builder();
161-
builder
162-
.insert(ret_expr.syntax().text_range().end(), format!(" {variant_name}(())"));
161+
builder.insert(expr_range.end(), format!(" {variant_name}(())"));
163162
let source_change = SourceChange::from_text_edit(
164163
expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
165164
builder.finish(),
@@ -172,8 +171,8 @@ fn add_missing_ok_or_some(
172171
}
173172

174173
let mut builder = TextEdit::builder();
175-
builder.insert(expr.syntax().text_range().start(), format!("{variant_name}("));
176-
builder.insert(expr.syntax().text_range().end(), ")".to_owned());
174+
builder.insert(expr_range.start(), format!("{variant_name}("));
175+
builder.insert(expr_range.end(), ")".to_owned());
177176
let source_change = SourceChange::from_text_edit(
178177
expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
179178
builder.finish(),
@@ -192,6 +191,7 @@ fn remove_unnecessary_wrapper(
192191
let db = ctx.sema.db;
193192
let root = db.parse_or_expand(expr_ptr.file_id);
194193
let expr = expr_ptr.value.to_node(&root);
194+
// FIXME: support inside MacroCall?
195195
let expr = ctx.sema.original_ast_node(expr)?;
196196

197197
let Expr::CallExpr(call_expr) = expr else {
@@ -278,6 +278,7 @@ fn remove_semicolon(
278278
return None;
279279
}
280280
let block = BlockExpr::cast(expr.syntax().clone())?;
281+
// FIXME: support inside MacroCall?
281282
let expr_before_semi =
282283
block.statements().last().and_then(|s| ExprStmt::cast(s.syntax().clone()))?;
283284
let type_before_semi = ctx.sema.type_of_expr(&expr_before_semi.expr()?)?.original();
@@ -311,16 +312,13 @@ fn str_ref_to_owned(
311312

312313
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
313314
let expr = expr_ptr.value.to_node(&root);
314-
let expr_range = expr.syntax().text_range();
315+
let hir::FileRange { file_id, range } = ctx.sema.original_range_opt(expr.syntax())?;
315316

316317
let to_owned = ".to_owned()".to_owned();
317318

318-
let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned);
319-
let source_change = SourceChange::from_text_edit(
320-
expr_ptr.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
321-
edit,
322-
);
323-
acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, expr_range));
319+
let edit = TextEdit::insert(range.end(), to_owned);
320+
let source_change = SourceChange::from_text_edit(file_id.file_id(ctx.sema.db), edit);
321+
acc.push(fix("str_ref_to_owned", "Add .to_owned() here", source_change, range));
324322

325323
Some(())
326324
}
@@ -566,6 +564,32 @@ fn div(x: i32, y: i32) -> Result<i32, ()> {
566564
}
567565
Ok(x / y)
568566
}
567+
"#,
568+
);
569+
570+
check_fix(
571+
r#"
572+
//- minicore: option, result
573+
macro_rules! identity { ($($t:tt)*) => ($($t)*) }
574+
identity! {
575+
fn div(x: i32, y: i32) -> Result<i32, ()> {
576+
if y == 0 {
577+
return Err(());
578+
}
579+
x / y$0
580+
}
581+
}
582+
"#,
583+
r#"
584+
macro_rules! identity { ($($t:tt)*) => ($($t)*) }
585+
identity! {
586+
fn div(x: i32, y: i32) -> Result<i32, ()> {
587+
if y == 0 {
588+
return Err(());
589+
}
590+
Ok(x / y)
591+
}
592+
}
569593
"#,
570594
);
571595
}
@@ -1037,6 +1061,29 @@ struct String;
10371061
10381062
fn test() -> String {
10391063
"a".to_owned()
1064+
}
1065+
"#,
1066+
);
1067+
1068+
check_fix(
1069+
r#"
1070+
macro_rules! identity { ($($t:tt)*) => ($($t)*) }
1071+
struct String;
1072+
1073+
identity! {
1074+
fn test() -> String {
1075+
"a"$0
1076+
}
1077+
}
1078+
"#,
1079+
r#"
1080+
macro_rules! identity { ($($t:tt)*) => ($($t)*) }
1081+
struct String;
1082+
1083+
identity! {
1084+
fn test() -> String {
1085+
"a".to_owned()
1086+
}
10401087
}
10411088
"#,
10421089
);

0 commit comments

Comments
 (0)