aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/references/rename.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/references/rename.rs')
-rw-r--r--crates/ide/src/references/rename.rs208
1 files changed, 201 insertions, 7 deletions
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 01fe3a1a1..50cc1f963 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -64,7 +64,7 @@ pub(crate) fn prepare_rename(
64 } 64 }
65 }; 65 };
66 let name_like = sema 66 let name_like = sema
67 .find_node_at_offset_with_descend(&syntax, position.offset) 67 .find_node_at_offset_with_descend(syntax, position.offset)
68 .ok_or_else(|| format_err!("No references found at position"))?; 68 .ok_or_else(|| format_err!("No references found at position"))?;
69 let node = match &name_like { 69 let node = match &name_like {
70 ast::NameLike::Name(it) => it.syntax(), 70 ast::NameLike::Name(it) => it.syntax(),
@@ -104,7 +104,7 @@ pub(crate) fn rename_with_semantics(
104 104
105 let def = find_definition(sema, syntax, position)?; 105 let def = find_definition(sema, syntax, position)?;
106 match def { 106 match def {
107 Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(&sema, module, new_name), 107 Definition::ModuleDef(ModuleDef::Module(module)) => rename_mod(sema, module, new_name),
108 Definition::SelfType(_) => bail!("Cannot rename `Self`"), 108 Definition::SelfType(_) => bail!("Cannot rename `Self`"),
109 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"), 109 Definition::ModuleDef(ModuleDef::BuiltinType(_)) => bail!("Cannot rename builtin type"),
110 def => rename_reference(sema, def, new_name), 110 def => rename_reference(sema, def, new_name),
@@ -170,7 +170,17 @@ fn find_definition(
170 NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db)) 170 NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db))
171 } 171 }
172 ast::NameLike::NameRef(name_ref) => { 172 ast::NameLike::NameRef(name_ref) => {
173 NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db)) 173 if let Some(def) =
174 NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db))
175 {
176 // if the name differs from the definitions name it has to be an alias
177 if def.name(sema.db).map_or(false, |it| it.to_string() != name_ref.text()) {
178 bail!("Renaming aliases is currently unsupported");
179 }
180 Some(def)
181 } else {
182 None
183 }
174 } 184 }
175 ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) 185 ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
176 .map(|class| NameRefClass::referenced(class, sema.db)) 186 .map(|class| NameRefClass::referenced(class, sema.db))
@@ -229,7 +239,7 @@ fn rename_mod(
229 239
230fn rename_reference( 240fn rename_reference(
231 sema: &Semantics<RootDatabase>, 241 sema: &Semantics<RootDatabase>,
232 def: Definition, 242 mut def: Definition,
233 new_name: &str, 243 new_name: &str,
234) -> RenameResult<SourceChange> { 244) -> RenameResult<SourceChange> {
235 let ident_kind = check_identifier(new_name)?; 245 let ident_kind = check_identifier(new_name)?;
@@ -275,14 +285,45 @@ fn rename_reference(
275 } 285 }
276 } 286 }
277 287
288 def = match def {
289 // HACK: resolve trait impl items to the item def of the trait definition
290 // so that we properly resolve all trait item references
291 Definition::ModuleDef(mod_def) => mod_def
292 .as_assoc_item(sema.db)
293 .and_then(|it| it.containing_trait_impl(sema.db))
294 .and_then(|it| {
295 it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) {
296 (hir::AssocItem::Function(trait_func), ModuleDef::Function(func))
297 if trait_func.name(sema.db) == func.name(sema.db) =>
298 {
299 Some(Definition::ModuleDef(ModuleDef::Function(trait_func)))
300 }
301 (hir::AssocItem::Const(trait_konst), ModuleDef::Const(konst))
302 if trait_konst.name(sema.db) == konst.name(sema.db) =>
303 {
304 Some(Definition::ModuleDef(ModuleDef::Const(trait_konst)))
305 }
306 (
307 hir::AssocItem::TypeAlias(trait_type_alias),
308 ModuleDef::TypeAlias(type_alias),
309 ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => {
310 Some(Definition::ModuleDef(ModuleDef::TypeAlias(trait_type_alias)))
311 }
312 _ => None,
313 })
314 })
315 .unwrap_or(def),
316 _ => def,
317 };
278 let usages = def.usages(sema).all(); 318 let usages = def.usages(sema).all();
319
279 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { 320 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
280 cov_mark::hit!(rename_underscore_multiple); 321 cov_mark::hit!(rename_underscore_multiple);
281 bail!("Cannot rename reference to `_` as it is being referenced multiple times"); 322 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
282 } 323 }
283 let mut source_change = SourceChange::default(); 324 let mut source_change = SourceChange::default();
284 source_change.extend(usages.iter().map(|(&file_id, references)| { 325 source_change.extend(usages.iter().map(|(&file_id, references)| {
285 (file_id, source_edit_from_references(&references, def, new_name)) 326 (file_id, source_edit_from_references(references, def, new_name))
286 })); 327 }));
287 328
288 let (file_id, edit) = source_edit_from_def(sema, def, new_name)?; 329 let (file_id, edit) = source_edit_from_def(sema, def, new_name)?;
@@ -372,7 +413,7 @@ fn rename_self_to_param(
372 let mut source_change = SourceChange::default(); 413 let mut source_change = SourceChange::default();
373 source_change.insert_source_edit(file_id.original_file(sema.db), edit); 414 source_change.insert_source_edit(file_id.original_file(sema.db), edit);
374 source_change.extend(usages.iter().map(|(&file_id, references)| { 415 source_change.extend(usages.iter().map(|(&file_id, references)| {
375 (file_id, source_edit_from_references(&references, def, new_name)) 416 (file_id, source_edit_from_references(references, def, new_name))
376 })); 417 }));
377 Ok(source_change) 418 Ok(source_change)
378} 419}
@@ -385,7 +426,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt
385 None 426 None
386 } 427 }
387 428
388 let impl_def = self_param.syntax().ancestors().find_map(|it| ast::Impl::cast(it))?; 429 let impl_def = self_param.syntax().ancestors().find_map(ast::Impl::cast)?;
389 let type_name = target_type_name(&impl_def)?; 430 let type_name = target_type_name(&impl_def)?;
390 431
391 let mut replacement_text = String::from(new_name); 432 let mut replacement_text = String::from(new_name);
@@ -1907,4 +1948,157 @@ impl Fo0 where Self: {}
1907"#, 1948"#,
1908 ); 1949 );
1909 } 1950 }
1951
1952 #[test]
1953 fn test_rename_fails_on_aliases() {
1954 check(
1955 "Baz",
1956 r#"
1957struct Foo;
1958use Foo as Bar$0;
1959"#,
1960 "error: Renaming aliases is currently unsupported",
1961 );
1962 check(
1963 "Baz",
1964 r#"
1965struct Foo;
1966use Foo as Bar;
1967use Bar$0;
1968"#,
1969 "error: Renaming aliases is currently unsupported",
1970 );
1971 }
1972
1973 #[test]
1974 fn test_rename_trait_method() {
1975 let res = r"
1976trait Foo {
1977 fn foo(&self) {
1978 self.foo();
1979 }
1980}
1981
1982impl Foo for () {
1983 fn foo(&self) {
1984 self.foo();
1985 }
1986}";
1987 check(
1988 "foo",
1989 r#"
1990trait Foo {
1991 fn bar$0(&self) {
1992 self.bar();
1993 }
1994}
1995
1996impl Foo for () {
1997 fn bar(&self) {
1998 self.bar();
1999 }
2000}"#,
2001 res,
2002 );
2003 check(
2004 "foo",
2005 r#"
2006trait Foo {
2007 fn bar(&self) {
2008 self.bar$0();
2009 }
2010}
2011
2012impl Foo for () {
2013 fn bar(&self) {
2014 self.bar();
2015 }
2016}"#,
2017 res,
2018 );
2019 check(
2020 "foo",
2021 r#"
2022trait Foo {
2023 fn bar(&self) {
2024 self.bar();
2025 }
2026}
2027
2028impl Foo for () {
2029 fn bar$0(&self) {
2030 self.bar();
2031 }
2032}"#,
2033 res,
2034 );
2035 check(
2036 "foo",
2037 r#"
2038trait Foo {
2039 fn bar(&self) {
2040 self.bar();
2041 }
2042}
2043
2044impl Foo for () {
2045 fn bar(&self) {
2046 self.bar$0();
2047 }
2048}"#,
2049 res,
2050 );
2051 }
2052
2053 #[test]
2054 fn test_rename_trait_const() {
2055 let res = r"
2056trait Foo {
2057 const FOO: ();
2058}
2059
2060impl Foo for () {
2061 const FOO: ();
2062}
2063fn f() { <()>::FOO; }";
2064 check(
2065 "FOO",
2066 r#"
2067trait Foo {
2068 const BAR$0: ();
2069}
2070
2071impl Foo for () {
2072 const BAR: ();
2073}
2074fn f() { <()>::BAR; }"#,
2075 res,
2076 );
2077 check(
2078 "FOO",
2079 r#"
2080trait Foo {
2081 const BAR: ();
2082}
2083
2084impl Foo for () {
2085 const BAR$0: ();
2086}
2087fn f() { <()>::BAR; }"#,
2088 res,
2089 );
2090 check(
2091 "FOO",
2092 r#"
2093trait Foo {
2094 const BAR: ();
2095}
2096
2097impl Foo for () {
2098 const BAR: ();
2099}
2100fn f() { <()>::BAR$0; }"#,
2101 res,
2102 );
2103 }
1910} 2104}