aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs21
-rw-r--r--crates/hir_def/src/nameres/collector.rs165
-rw-r--r--crates/ide/src/references/rename.rs71
3 files changed, 127 insertions, 130 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/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 28b73c3a1..d8fabe49b 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -91,7 +91,6 @@ pub(super) fn collect_defs(
91 resolved_imports: Vec::new(), 91 resolved_imports: Vec::new(),
92 92
93 unexpanded_macros: Vec::new(), 93 unexpanded_macros: Vec::new(),
94 unexpanded_attribute_macros: Vec::new(),
95 mod_dirs: FxHashMap::default(), 94 mod_dirs: FxHashMap::default(),
96 cfg_options, 95 cfg_options,
97 proc_macros, 96 proc_macros,
@@ -202,15 +201,14 @@ struct ImportDirective {
202#[derive(Clone, Debug, Eq, PartialEq)] 201#[derive(Clone, Debug, Eq, PartialEq)]
203struct MacroDirective { 202struct MacroDirective {
204 module_id: LocalModuleId, 203 module_id: LocalModuleId,
205 ast_id: AstIdWithPath<ast::MacroCall>,
206 legacy: Option<MacroCallId>,
207 depth: usize, 204 depth: usize,
205 kind: MacroDirectiveKind,
208} 206}
209 207
210#[derive(Clone, Debug, Eq, PartialEq)] 208#[derive(Clone, Debug, Eq, PartialEq)]
211struct DeriveDirective { 209enum MacroDirectiveKind {
212 module_id: LocalModuleId, 210 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> },
213 ast_id: AstIdWithPath<ast::Item>, 211 Derive { ast_id: AstIdWithPath<ast::Item> },
214} 212}
215 213
216struct DefData<'a> { 214struct DefData<'a> {
@@ -228,7 +226,6 @@ struct DefCollector<'a> {
228 unresolved_imports: Vec<ImportDirective>, 226 unresolved_imports: Vec<ImportDirective>,
229 resolved_imports: Vec<ImportDirective>, 227 resolved_imports: Vec<ImportDirective>,
230 unexpanded_macros: Vec<MacroDirective>, 228 unexpanded_macros: Vec<MacroDirective>,
231 unexpanded_attribute_macros: Vec<DeriveDirective>,
232 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 229 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
233 cfg_options: &'a CfgOptions, 230 cfg_options: &'a CfgOptions,
234 /// List of procedural macros defined by this crate. This is read from the dynamic library 231 /// List of procedural macros defined by this crate. This is read from the dynamic library
@@ -782,60 +779,58 @@ impl DefCollector<'_> {
782 779
783 fn resolve_macros(&mut self) -> ReachedFixedPoint { 780 fn resolve_macros(&mut self) -> ReachedFixedPoint {
784 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 781 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
785 let mut attribute_macros =
786 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
787 let mut resolved = Vec::new(); 782 let mut resolved = Vec::new();
788 let mut res = ReachedFixedPoint::Yes; 783 let mut res = ReachedFixedPoint::Yes;
789 macros.retain(|directive| { 784 macros.retain(|directive| {
790 if let Some(call_id) = directive.legacy { 785 match &directive.kind {
791 res = ReachedFixedPoint::No; 786 MacroDirectiveKind::FnLike { ast_id, legacy } => {
792 resolved.push((directive.module_id, call_id, directive.depth)); 787 if let Some(call_id) = legacy {
793 return false; 788 res = ReachedFixedPoint::No;
794 } 789 resolved.push((directive.module_id, *call_id, directive.depth));
790 return false;
791 }
795 792
796 match macro_call_as_call_id( 793 match macro_call_as_call_id(
797 &directive.ast_id, 794 ast_id,
798 self.db,
799 self.def_map.krate,
800 |path| {
801 let resolved_res = self.def_map.resolve_path_fp_with_macro(
802 self.db, 795 self.db,
803 ResolveMode::Other, 796 self.def_map.krate,
804 directive.module_id, 797 |path| {
805 &path, 798 let resolved_res = self.def_map.resolve_path_fp_with_macro(
806 BuiltinShadowMode::Module, 799 self.db,
807 ); 800 ResolveMode::Other,
808 resolved_res.resolved_def.take_macros() 801 directive.module_id,
809 }, 802 &path,
810 &mut |_err| (), 803 BuiltinShadowMode::Module,
811 ) { 804 );
812 Ok(Ok(call_id)) => { 805 resolved_res.resolved_def.take_macros()
813 resolved.push((directive.module_id, call_id, directive.depth)); 806 },
814 res = ReachedFixedPoint::No; 807 &mut |_err| (),
815 return false; 808 ) {
809 Ok(Ok(call_id)) => {
810 resolved.push((directive.module_id, call_id, directive.depth));
811 res = ReachedFixedPoint::No;
812 return false;
813 }
814 Err(UnresolvedMacro) | Ok(Err(_)) => {}
815 }
816 } 816 }
817 Err(UnresolvedMacro) | Ok(Err(_)) => {} 817 MacroDirectiveKind::Derive { ast_id } => {
818 } 818 match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| {
819 819 self.resolve_derive_macro(directive.module_id, &path)
820 true 820 }) {
821 }); 821 Ok(call_id) => {
822 attribute_macros.retain(|directive| { 822 resolved.push((directive.module_id, call_id, 0));
823 match derive_macro_as_call_id(&directive.ast_id, self.db, self.def_map.krate, |path| { 823 res = ReachedFixedPoint::No;
824 self.resolve_derive_macro(&directive, &path) 824 return false;
825 }) { 825 }
826 Ok(call_id) => { 826 Err(UnresolvedMacro) => (),
827 resolved.push((directive.module_id, call_id, 0)); 827 }
828 res = ReachedFixedPoint::No;
829 return false;
830 } 828 }
831 Err(UnresolvedMacro) => (),
832 } 829 }
833 830
834 true 831 true
835 }); 832 });
836
837 self.unexpanded_macros = macros; 833 self.unexpanded_macros = macros;
838 self.unexpanded_attribute_macros = attribute_macros;
839 834
840 for (module_id, macro_call_id, depth) in resolved { 835 for (module_id, macro_call_id, depth) in resolved {
841 self.collect_macro_expansion(module_id, macro_call_id, depth); 836 self.collect_macro_expansion(module_id, macro_call_id, depth);
@@ -844,15 +839,11 @@ impl DefCollector<'_> {
844 res 839 res
845 } 840 }
846 841
847 fn resolve_derive_macro( 842 fn resolve_derive_macro(&self, module: LocalModuleId, path: &ModPath) -> Option<MacroDefId> {
848 &self,
849 directive: &DeriveDirective,
850 path: &ModPath,
851 ) -> Option<MacroDefId> {
852 let resolved_res = self.def_map.resolve_path_fp_with_macro( 843 let resolved_res = self.def_map.resolve_path_fp_with_macro(
853 self.db, 844 self.db,
854 ResolveMode::Other, 845 ResolveMode::Other,
855 directive.module_id, 846 module,
856 &path, 847 &path,
857 BuiltinShadowMode::Module, 848 BuiltinShadowMode::Module,
858 ); 849 );
@@ -912,33 +903,35 @@ impl DefCollector<'_> {
912 // Emit diagnostics for all remaining unexpanded macros. 903 // Emit diagnostics for all remaining unexpanded macros.
913 904
914 for directive in &self.unexpanded_macros { 905 for directive in &self.unexpanded_macros {
915 let mut error = None; 906 match &directive.kind {
916 match macro_call_as_call_id( 907 MacroDirectiveKind::FnLike { ast_id, .. } => match macro_call_as_call_id(
917 &directive.ast_id, 908 ast_id,
918 self.db, 909 self.db,
919 self.def_map.krate, 910 self.def_map.krate,
920 |path| { 911 |path| {
921 let resolved_res = self.def_map.resolve_path_fp_with_macro( 912 let resolved_res = self.def_map.resolve_path_fp_with_macro(
922 self.db, 913 self.db,
923 ResolveMode::Other, 914 ResolveMode::Other,
924 directive.module_id, 915 directive.module_id,
925 &path, 916 &path,
926 BuiltinShadowMode::Module, 917 BuiltinShadowMode::Module,
927 ); 918 );
928 resolved_res.resolved_def.take_macros() 919 resolved_res.resolved_def.take_macros()
929 }, 920 },
930 &mut |e| { 921 &mut |_| (),
931 error.get_or_insert(e); 922 ) {
923 Ok(_) => (),
924 Err(UnresolvedMacro) => {
925 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
926 directive.module_id,
927 ast_id.ast_id,
928 ));
929 }
932 }, 930 },
933 ) { 931 MacroDirectiveKind::Derive { .. } => {
934 Ok(_) => (), 932 // FIXME: we might want to diagnose this too
935 Err(UnresolvedMacro) => {
936 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
937 directive.module_id,
938 directive.ast_id.ast_id,
939 ));
940 } 933 }
941 }; 934 }
942 } 935 }
943 936
944 // Emit diagnostics for all remaining unresolved imports. 937 // Emit diagnostics for all remaining unresolved imports.
@@ -1380,9 +1373,11 @@ impl ModCollector<'_, '_> {
1380 Some(derive_macros) => { 1373 Some(derive_macros) => {
1381 for path in derive_macros { 1374 for path in derive_macros {
1382 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); 1375 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
1383 self.def_collector 1376 self.def_collector.unexpanded_macros.push(MacroDirective {
1384 .unexpanded_attribute_macros 1377 module_id: self.module_id,
1385 .push(DeriveDirective { module_id: self.module_id, ast_id }); 1378 depth: self.macro_depth + 1,
1379 kind: MacroDirectiveKind::Derive { ast_id },
1380 });
1386 } 1381 }
1387 } 1382 }
1388 None => { 1383 None => {
@@ -1497,9 +1492,8 @@ impl ModCollector<'_, '_> {
1497 1492
1498 self.def_collector.unexpanded_macros.push(MacroDirective { 1493 self.def_collector.unexpanded_macros.push(MacroDirective {
1499 module_id: self.module_id, 1494 module_id: self.module_id,
1500 ast_id,
1501 legacy: None,
1502 depth: self.macro_depth + 1, 1495 depth: self.macro_depth + 1,
1496 kind: MacroDirectiveKind::FnLike { ast_id, legacy: None },
1503 }); 1497 });
1504 } 1498 }
1505 1499
@@ -1542,7 +1536,6 @@ mod tests {
1542 unresolved_imports: Vec::new(), 1536 unresolved_imports: Vec::new(),
1543 resolved_imports: Vec::new(), 1537 resolved_imports: Vec::new(),
1544 unexpanded_macros: Vec::new(), 1538 unexpanded_macros: Vec::new(),
1545 unexpanded_attribute_macros: Vec::new(),
1546 mod_dirs: FxHashMap::default(), 1539 mod_dirs: FxHashMap::default(),
1547 cfg_options: &CfgOptions::default(), 1540 cfg_options: &CfgOptions::default(),
1548 proc_macros: Default::default(), 1541 proc_macros: Default::default(),
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