Skip to content

Commit 6fc7689

Browse files
bors[bot]Veykril
andauthored
Merge #9861
9861: fix: `extract_variable` handles selection ranges better r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents f438dbb + 6045059 commit 6fc7689

File tree

2 files changed

+57
-22
lines changed

2 files changed

+57
-22
lines changed

crates/ide_assists/src/handlers/extract_function.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,8 +1080,7 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option<SyntaxNod
10801080
fn make_call(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String {
10811081
let ret_ty = fun.return_type(ctx);
10821082

1083-
let args = fun.params.iter().map(|param| param.to_arg(ctx));
1084-
let args = make::arg_list(args);
1083+
let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx)));
10851084
let name = fun.name.clone();
10861085
let call_expr = if fun.self_param.is_some() {
10871086
let self_arg = make::expr_path(make::ext::ident_path("self"));
@@ -1103,12 +1102,12 @@ fn make_call(ctx: &AssistContext, fun: &Function, indent: IndentLevel) -> String
11031102
[var] => {
11041103
format_to!(buf, "let {}{} = ", mut_modifier(var), var.local.name(ctx.db()).unwrap())
11051104
}
1106-
[v0, vs @ ..] => {
1105+
vars => {
11071106
buf.push_str("let (");
1108-
format_to!(buf, "{}{}", mut_modifier(v0), v0.local.name(ctx.db()).unwrap());
1109-
for var in vs {
1110-
format_to!(buf, ", {}{}", mut_modifier(var), var.local.name(ctx.db()).unwrap());
1111-
}
1107+
let bindings = vars.iter().format_with(", ", |local, f| {
1108+
f(&format_args!("{}{}", mut_modifier(local), local.local.name(ctx.db()).unwrap()))
1109+
});
1110+
format_to!(buf, "{}", bindings);
11121111
buf.push_str(") = ");
11131112
}
11141113
}

crates/ide_assists/src/handlers/inline_local_variable.rs

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use either::Either;
2-
use hir::PathResolution;
2+
use hir::{PathResolution, Semantics};
33
use ide_db::{
4+
base_db::{FileId, FileRange},
45
defs::Definition,
56
search::{FileReference, UsageSearchResult},
7+
RootDatabase,
68
};
79
use syntax::{
810
ast::{self, AstNode, AstToken, NameOwner},
@@ -31,8 +33,15 @@ use crate::{
3133
// }
3234
// ```
3335
pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36+
let FileRange { file_id, range } = ctx.frange;
3437
let InlineData { let_stmt, delete_let, references, target } =
35-
inline_let(ctx).or_else(|| inline_usage(ctx))?;
38+
if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() {
39+
inline_let(&ctx.sema, let_stmt, range, file_id)
40+
} else if let Some(path_expr) = ctx.find_node_at_offset::<ast::PathExpr>() {
41+
inline_usage(&ctx.sema, path_expr, range, file_id)
42+
} else {
43+
None
44+
}?;
3645
let initializer_expr = let_stmt.initializer()?;
3746

3847
let delete_range = delete_let.then(|| {
@@ -139,8 +148,12 @@ struct InlineData {
139148
references: Vec<FileReference>,
140149
}
141150

142-
fn inline_let(ctx: &AssistContext) -> Option<InlineData> {
143-
let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
151+
fn inline_let(
152+
sema: &Semantics<RootDatabase>,
153+
let_stmt: ast::LetStmt,
154+
range: TextRange,
155+
file_id: FileId,
156+
) -> Option<InlineData> {
144157
let bind_pat = match let_stmt.pat()? {
145158
ast::Pat::IdentPat(pat) => pat,
146159
_ => return None,
@@ -149,14 +162,14 @@ fn inline_let(ctx: &AssistContext) -> Option<InlineData> {
149162
cov_mark::hit!(test_not_inline_mut_variable);
150163
return None;
151164
}
152-
if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
165+
if !bind_pat.syntax().text_range().contains_range(range) {
153166
cov_mark::hit!(not_applicable_outside_of_bind_pat);
154167
return None;
155168
}
156169

157-
let local = ctx.sema.to_def(&bind_pat)?;
158-
let UsageSearchResult { mut references } = Definition::Local(local).usages(&ctx.sema).all();
159-
match references.remove(&ctx.frange.file_id) {
170+
let local = sema.to_def(&bind_pat)?;
171+
let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all();
172+
match references.remove(&file_id) {
160173
Some(references) => Some(InlineData {
161174
let_stmt,
162175
delete_let: true,
@@ -170,29 +183,37 @@ fn inline_let(ctx: &AssistContext) -> Option<InlineData> {
170183
}
171184
}
172185

173-
fn inline_usage(ctx: &AssistContext) -> Option<InlineData> {
174-
let path_expr = ctx.find_node_at_offset::<ast::PathExpr>()?;
186+
fn inline_usage(
187+
sema: &Semantics<RootDatabase>,
188+
path_expr: ast::PathExpr,
189+
range: TextRange,
190+
file_id: FileId,
191+
) -> Option<InlineData> {
175192
let path = path_expr.path()?;
176193
let name = path.as_single_name_ref()?;
194+
if !name.syntax().text_range().contains_range(range) {
195+
cov_mark::hit!(test_not_inline_selection_too_broad);
196+
return None;
197+
}
177198

178-
let local = match ctx.sema.resolve_path(&path)? {
199+
let local = match sema.resolve_path(&path)? {
179200
PathResolution::Local(local) => local,
180201
_ => return None,
181202
};
182-
if local.is_mut(ctx.db()) {
203+
if local.is_mut(sema.db) {
183204
cov_mark::hit!(test_not_inline_mut_variable_use);
184205
return None;
185206
}
186207

187-
let bind_pat = match local.source(ctx.db()).value {
208+
let bind_pat = match local.source(sema.db).value {
188209
Either::Left(ident) => ident,
189210
_ => return None,
190211
};
191212

192213
let let_stmt = ast::LetStmt::cast(bind_pat.syntax().parent()?)?;
193214

194-
let UsageSearchResult { mut references } = Definition::Local(local).usages(&ctx.sema).all();
195-
let mut references = references.remove(&ctx.frange.file_id)?;
215+
let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all();
216+
let mut references = references.remove(&file_id)?;
196217
let delete_let = references.len() == 1;
197218
references.retain(|fref| fref.name.as_name_ref() == Some(&name));
198219

@@ -875,6 +896,21 @@ fn f() {
875896
let xyz$0 = 0;
876897
m!(xyz); // replacing it would break the macro
877898
}
899+
"#,
900+
);
901+
}
902+
903+
#[test]
904+
fn test_not_inline_selection_too_broad() {
905+
cov_mark::check!(test_not_inline_selection_too_broad);
906+
check_assist_not_applicable(
907+
inline_local_variable,
908+
r#"
909+
fn f() {
910+
let foo = 0;
911+
let bar = 0;
912+
$0foo + bar$0;
913+
}
878914
"#,
879915
);
880916
}

0 commit comments

Comments
 (0)