aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-03-23 15:50:36 +0000
committerLukas Wirth <[email protected]>2021-03-23 15:54:21 +0000
commit638dcac092c130aa817d3ca94d3ed743a6d42938 (patch)
tree18c813e15a53f96d8a10527ca0c3263b50307879 /crates
parent0469280c8affdc6bdb96ad5bf02073725c5cfd06 (diff)
Make more use of the HIR in rename::rename_to_self
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs21
-rw-r--r--crates/ide/src/references/rename.rs71
2 files changed, 48 insertions, 44 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 5da6a0340..bdc1ad852 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -852,6 +852,7 @@ impl Function {
852 }) 852 })
853 .collect() 853 .collect()
854 } 854 }
855
855 pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> { 856 pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param>> {
856 if self.self_param(db).is_none() { 857 if self.self_param(db).is_none() {
857 return None; 858 return None;
@@ -909,7 +910,7 @@ impl From<hir_ty::Mutability> for Access {
909 } 910 }
910} 911}
911 912
912#[derive(Debug)] 913#[derive(Clone, Debug)]
913pub struct Param { 914pub struct Param {
914 func: Function, 915 func: Function,
915 /// The index in parameter list, including self parameter. 916 /// The index in parameter list, including self parameter.
@@ -922,13 +923,25 @@ impl Param {
922 &self.ty 923 &self.ty
923 } 924 }
924 925
926 pub fn as_local(&self, db: &dyn HirDatabase) -> Local {
927 let parent = DefWithBodyId::FunctionId(self.func.into());
928 let body = db.body(parent);
929 Local { parent, pat_id: body.params[self.idx] }
930 }
931
925 pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> { 932 pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
926 let params = self.func.source(db)?.value.param_list()?; 933 self.source(db).and_then(|p| p.value.pat())
934 }
935
936 pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Param>> {
937 let InFile { file_id, value } = self.func.source(db)?;
938 let params = value.param_list()?;
927 if params.self_param().is_some() { 939 if params.self_param().is_some() {
928 params.params().nth(self.idx.checked_sub(1)?)?.pat() 940 params.params().nth(self.idx.checked_sub(1)?)
929 } else { 941 } else {
930 params.params().nth(self.idx)?.pat() 942 params.params().nth(self.idx)
931 } 943 }
944 .map(|value| InFile { file_id, value })
932 } 945 }
933} 946}
934 947
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 5340b638a..b1ca6d50f 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,8 +1,11 @@
1//! FIXME: write short doc here 1//! Renaming functionality
2//!
3//! All reference and file rename requests go through here where the corresponding [`SourceChange`]s
4//! will be calculated.
2use std::fmt::{self, Display}; 5use std::fmt::{self, Display};
3 6
4use either::Either; 7use either::Either;
5use hir::{HasSource, InFile, Module, ModuleDef, ModuleSource, Semantics}; 8use hir::{AsAssocItem, InFile, Module, ModuleDef, ModuleSource, Semantics};
6use ide_db::{ 9use ide_db::{
7 base_db::{AnchoredPathBuf, FileId}, 10 base_db::{AnchoredPathBuf, FileId},
8 defs::{Definition, NameClass, NameRefClass}, 11 defs::{Definition, NameClass, NameRefClass},
@@ -196,7 +199,7 @@ fn rename_mod(
196 file_id, 199 file_id,
197 TextEdit::replace(name.syntax().text_range(), new_name.to_string()), 200 TextEdit::replace(name.syntax().text_range(), new_name.to_string()),
198 ), 201 ),
199 _ => unreachable!(), 202 _ => never!("Module source node is missing a name"),
200 } 203 }
201 } 204 }
202 let def = Definition::ModuleDef(ModuleDef::Module(module)); 205 let def = Definition::ModuleDef(ModuleDef::Module(module));
@@ -275,46 +278,32 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
275 278
276 let fn_def = match local.parent(sema.db) { 279 let fn_def = match local.parent(sema.db) {
277 hir::DefWithBody::Function(func) => func, 280 hir::DefWithBody::Function(func) => func,
278 _ => bail!("Cannot rename non-param local to self"), 281 _ => bail!("Cannot rename local to self outside of function"),
279 }; 282 };
280 283
281 // FIXME: reimplement this on the hir instead 284 if let Some(_) = fn_def.self_param(sema.db) {
282 // as of the time of this writing params in hir don't keep their names
283 let fn_ast = fn_def
284 .source(sema.db)
285 .ok_or_else(|| format_err!("Cannot rename non-param local to self"))?
286 .value;
287
288 let first_param_range = fn_ast
289 .param_list()
290 .and_then(|p| p.params().next())
291 .ok_or_else(|| format_err!("Method has no parameters"))?
292 .syntax()
293 .text_range();
294 let InFile { file_id, value: local_source } = local.source(sema.db);
295 match local_source {
296 either::Either::Left(pat)
297 if !first_param_range.contains_range(pat.syntax().text_range()) =>
298 {
299 bail!("Only the first parameter can be self");
300 }
301 _ => (),
302 }
303
304 let impl_block = fn_ast
305 .syntax()
306 .ancestors()
307 .find_map(|node| ast::Impl::cast(node))
308 .and_then(|def| sema.to_def(&def))
309 .ok_or_else(|| format_err!("No impl block found for function"))?;
310 if fn_def.self_param(sema.db).is_some() {
311 bail!("Method already has a self parameter"); 285 bail!("Method already has a self parameter");
312 } 286 }
313 287
314 let params = fn_def.assoc_fn_params(sema.db); 288 let params = fn_def.assoc_fn_params(sema.db);
315 let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?; 289 let first_param = params
290 .first()
291 .ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?;
292 if first_param.as_local(sema.db) != local {
293 bail!("Only the first parameter may be renamed to self");
294 }
295
296 let assoc_item = fn_def
297 .as_assoc_item(sema.db)
298 .ok_or_else(|| format_err!("Cannot rename parameter to self for free function"))?;
299 let impl_ = match assoc_item.container(sema.db) {
300 hir::AssocItemContainer::Trait(_) => {
301 bail!("Cannot rename parameter to self for trait functions");
302 }
303 hir::AssocItemContainer::Impl(impl_) => impl_,
304 };
316 let first_param_ty = first_param.ty(); 305 let first_param_ty = first_param.ty();
317 let impl_ty = impl_block.target_ty(sema.db); 306 let impl_ty = impl_.target_ty(sema.db);
318 let (ty, self_param) = if impl_ty.remove_ref().is_some() { 307 let (ty, self_param) = if impl_ty.remove_ref().is_some() {
319 // if the impl is a ref to the type we can just match the `&T` with self directly 308 // if the impl is a ref to the type we can just match the `&T` with self directly
320 (first_param_ty.clone(), "self") 309 (first_param_ty.clone(), "self")
@@ -328,6 +317,9 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
328 bail!("Parameter type differs from impl block type"); 317 bail!("Parameter type differs from impl block type");
329 } 318 }
330 319
320 let InFile { file_id, value: param_source } =
321 first_param.source(sema.db).ok_or_else(|| format_err!("No source for parameter found"))?;
322
331 let def = Definition::Local(local); 323 let def = Definition::Local(local);
332 let usages = def.usages(sema).all(); 324 let usages = def.usages(sema).all();
333 let mut source_change = SourceChange::default(); 325 let mut source_change = SourceChange::default();
@@ -336,9 +328,8 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
336 })); 328 }));
337 source_change.insert_source_edit( 329 source_change.insert_source_edit(
338 file_id.original_file(sema.db), 330 file_id.original_file(sema.db),
339 TextEdit::replace(first_param_range, String::from(self_param)), 331 TextEdit::replace(param_source.syntax().text_range(), String::from(self_param)),
340 ); 332 );
341
342 Ok(source_change) 333 Ok(source_change)
343} 334}
344 335
@@ -1361,7 +1352,7 @@ fn f(foo$0: &mut Foo) -> i32 {
1361 foo.i 1352 foo.i
1362} 1353}
1363"#, 1354"#,
1364 "error: No impl block found for function", 1355 "error: Cannot rename parameter to self for free function",
1365 ); 1356 );
1366 check( 1357 check(
1367 "self", 1358 "self",
@@ -1391,7 +1382,7 @@ impl Foo {
1391 } 1382 }
1392} 1383}
1393"#, 1384"#,
1394 "error: Only the first parameter can be self", 1385 "error: Only the first parameter may be renamed to self",
1395 ); 1386 );
1396 } 1387 }
1397 1388