diff options
Diffstat (limited to 'crates/ide/src/references')
-rw-r--r-- | crates/ide/src/references/rename.rs | 688 |
1 files changed, 365 insertions, 323 deletions
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index 854bf194e..4df189c98 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs | |||
@@ -1,29 +1,27 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::{ | 2 | use std::fmt::{self, Display}; |
3 | convert::TryInto, | ||
4 | error::Error, | ||
5 | fmt::{self, Display}, | ||
6 | }; | ||
7 | 3 | ||
8 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 4 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; |
9 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}; | ||
10 | use ide_db::{ | 5 | use ide_db::{ |
6 | base_db::{AnchoredPathBuf, FileId, FileRange}, | ||
11 | defs::{Definition, NameClass, NameRefClass}, | 7 | defs::{Definition, NameClass, NameRefClass}, |
8 | search::FileReference, | ||
12 | RootDatabase, | 9 | RootDatabase, |
13 | }; | 10 | }; |
14 | use syntax::{ | 11 | use syntax::{ |
15 | algo::find_node_at_offset, | 12 | algo::find_node_at_offset, |
16 | ast::{self, NameOwner}, | 13 | ast::{self, NameOwner}, |
17 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, | 14 | lex_single_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, T, |
18 | }; | 15 | }; |
19 | use test_utils::mark; | 16 | use test_utils::mark; |
20 | use text_edit::TextEdit; | 17 | use text_edit::TextEdit; |
21 | 18 | ||
22 | use crate::{ | 19 | use crate::{ |
23 | references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind, | 20 | FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, |
24 | SourceChange, SourceFileEdit, TextRange, TextSize, | 21 | TextRange, |
25 | }; | 22 | }; |
26 | 23 | ||
24 | type RenameResult<T> = Result<T, RenameError>; | ||
27 | #[derive(Debug)] | 25 | #[derive(Debug)] |
28 | pub struct RenameError(pub(crate) String); | 26 | pub struct RenameError(pub(crate) String); |
29 | 27 | ||
@@ -33,27 +31,27 @@ impl fmt::Display for RenameError { | |||
33 | } | 31 | } |
34 | } | 32 | } |
35 | 33 | ||
36 | impl Error for RenameError {} | 34 | macro_rules! format_err { |
35 | ($fmt:expr) => {RenameError(format!($fmt))}; | ||
36 | ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))} | ||
37 | } | ||
38 | |||
39 | macro_rules! bail { | ||
40 | ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))} | ||
41 | } | ||
37 | 42 | ||
38 | pub(crate) fn prepare_rename( | 43 | pub(crate) fn prepare_rename( |
39 | db: &RootDatabase, | 44 | db: &RootDatabase, |
40 | position: FilePosition, | 45 | position: FilePosition, |
41 | ) -> Result<RangeInfo<()>, RenameError> { | 46 | ) -> RenameResult<RangeInfo<()>> { |
42 | let sema = Semantics::new(db); | 47 | let sema = Semantics::new(db); |
43 | let source_file = sema.parse(position.file_id); | 48 | let source_file = sema.parse(position.file_id); |
44 | let syntax = source_file.syntax(); | 49 | let syntax = source_file.syntax(); |
45 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { | 50 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { |
46 | rename_mod(&sema, position, module, "dummy") | 51 | rename_mod(&sema, position, module, "dummy") |
47 | } else if let Some(self_token) = | ||
48 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
49 | { | ||
50 | rename_self_to_param(&sema, position, self_token, "dummy") | ||
51 | } else { | 52 | } else { |
52 | let range = match find_all_refs(&sema, position, None) { | 53 | let RangeInfo { range, .. } = find_all_refs(&sema, position)?; |
53 | Some(RangeInfo { range, .. }) => range, | 54 | Ok(RangeInfo::new(range, SourceChange::default())) |
54 | None => return Err(RenameError("No references found at position".to_string())), | ||
55 | }; | ||
56 | Ok(RangeInfo::new(range, SourceChange::from(vec![]))) | ||
57 | } | 55 | } |
58 | .map(|info| RangeInfo::new(info.range, ())) | 56 | .map(|info| RangeInfo::new(info.range, ())) |
59 | } | 57 | } |
@@ -62,7 +60,7 @@ pub(crate) fn rename( | |||
62 | db: &RootDatabase, | 60 | db: &RootDatabase, |
63 | position: FilePosition, | 61 | position: FilePosition, |
64 | new_name: &str, | 62 | new_name: &str, |
65 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 63 | ) -> RenameResult<RangeInfo<SourceChange>> { |
66 | let sema = Semantics::new(db); | 64 | let sema = Semantics::new(db); |
67 | rename_with_semantics(&sema, position, new_name) | 65 | rename_with_semantics(&sema, position, new_name) |
68 | } | 66 | } |
@@ -71,42 +69,14 @@ pub(crate) fn rename_with_semantics( | |||
71 | sema: &Semantics<RootDatabase>, | 69 | sema: &Semantics<RootDatabase>, |
72 | position: FilePosition, | 70 | position: FilePosition, |
73 | new_name: &str, | 71 | new_name: &str, |
74 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 72 | ) -> RenameResult<RangeInfo<SourceChange>> { |
75 | let is_lifetime_name = match lex_single_syntax_kind(new_name) { | ||
76 | Some(res) => match res { | ||
77 | (SyntaxKind::IDENT, _) => false, | ||
78 | (SyntaxKind::UNDERSCORE, _) => false, | ||
79 | (SyntaxKind::SELF_KW, _) => return rename_to_self(&sema, position), | ||
80 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => true, | ||
81 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
82 | return Err(RenameError(format!( | ||
83 | "Invalid name `{0}`: Cannot rename lifetime to {0}", | ||
84 | new_name | ||
85 | ))) | ||
86 | } | ||
87 | (_, Some(syntax_error)) => { | ||
88 | return Err(RenameError(format!("Invalid name `{}`: {}", new_name, syntax_error))) | ||
89 | } | ||
90 | (_, None) => { | ||
91 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | ||
92 | } | ||
93 | }, | ||
94 | None => return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))), | ||
95 | }; | ||
96 | |||
97 | let source_file = sema.parse(position.file_id); | 73 | let source_file = sema.parse(position.file_id); |
98 | let syntax = source_file.syntax(); | 74 | let syntax = source_file.syntax(); |
99 | // this is here to prevent lifetime renames from happening on modules and self | 75 | |
100 | if is_lifetime_name { | 76 | if let Some(module) = find_module_at_offset(&sema, position, syntax) { |
101 | rename_reference(&sema, position, new_name, is_lifetime_name) | ||
102 | } else if let Some(module) = find_module_at_offset(&sema, position, syntax) { | ||
103 | rename_mod(&sema, position, module, new_name) | 77 | rename_mod(&sema, position, module, new_name) |
104 | } else if let Some(self_token) = | ||
105 | syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
106 | { | ||
107 | rename_self_to_param(&sema, position, self_token, new_name) | ||
108 | } else { | 78 | } else { |
109 | rename_reference(&sema, position, new_name, is_lifetime_name) | 79 | rename_reference(&sema, position, new_name) |
110 | } | 80 | } |
111 | } | 81 | } |
112 | 82 | ||
@@ -127,6 +97,33 @@ pub(crate) fn will_rename_file( | |||
127 | Some(change) | 97 | Some(change) |
128 | } | 98 | } |
129 | 99 | ||
100 | #[derive(Copy, Clone, Debug, PartialEq)] | ||
101 | enum IdentifierKind { | ||
102 | Ident, | ||
103 | Lifetime, | ||
104 | ToSelf, | ||
105 | Underscore, | ||
106 | } | ||
107 | |||
108 | fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> { | ||
109 | match lex_single_syntax_kind(new_name) { | ||
110 | Some(res) => match res { | ||
111 | (SyntaxKind::IDENT, _) => Ok(IdentifierKind::Ident), | ||
112 | (T![_], _) => Ok(IdentifierKind::Underscore), | ||
113 | (T![self], _) => Ok(IdentifierKind::ToSelf), | ||
114 | (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { | ||
115 | Ok(IdentifierKind::Lifetime) | ||
116 | } | ||
117 | (SyntaxKind::LIFETIME_IDENT, _) => { | ||
118 | bail!("Invalid name `{0}`: Cannot rename lifetime to {0}", new_name) | ||
119 | } | ||
120 | (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), | ||
121 | (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), | ||
122 | }, | ||
123 | None => bail!("Invalid name `{}`: not an identifier", new_name), | ||
124 | } | ||
125 | } | ||
126 | |||
130 | fn find_module_at_offset( | 127 | fn find_module_at_offset( |
131 | sema: &Semantics<RootDatabase>, | 128 | sema: &Semantics<RootDatabase>, |
132 | position: FilePosition, | 129 | position: FilePosition, |
@@ -155,39 +152,53 @@ fn find_module_at_offset( | |||
155 | Some(module) | 152 | Some(module) |
156 | } | 153 | } |
157 | 154 | ||
158 | fn source_edit_from_reference( | 155 | fn find_all_refs( |
156 | sema: &Semantics<RootDatabase>, | ||
157 | position: FilePosition, | ||
158 | ) -> RenameResult<RangeInfo<ReferenceSearchResult>> { | ||
159 | crate::references::find_all_refs(sema, position, None) | ||
160 | .ok_or_else(|| format_err!("No references found at position")) | ||
161 | } | ||
162 | |||
163 | fn source_edit_from_references( | ||
159 | sema: &Semantics<RootDatabase>, | 164 | sema: &Semantics<RootDatabase>, |
160 | reference: Reference, | 165 | file_id: FileId, |
166 | references: &[FileReference], | ||
161 | new_name: &str, | 167 | new_name: &str, |
162 | ) -> SourceFileEdit { | 168 | ) -> (FileId, TextEdit) { |
163 | let mut replacement_text = String::new(); | 169 | let mut edit = TextEdit::builder(); |
164 | let range = match reference.kind { | 170 | for reference in references { |
165 | ReferenceKind::FieldShorthandForField => { | 171 | let mut replacement_text = String::new(); |
166 | mark::hit!(test_rename_struct_field_for_shorthand); | 172 | let range = match reference.kind { |
167 | replacement_text.push_str(new_name); | 173 | ReferenceKind::FieldShorthandForField => { |
168 | replacement_text.push_str(": "); | 174 | mark::hit!(test_rename_struct_field_for_shorthand); |
169 | TextRange::new(reference.file_range.range.start(), reference.file_range.range.start()) | 175 | replacement_text.push_str(new_name); |
170 | } | 176 | replacement_text.push_str(": "); |
171 | ReferenceKind::FieldShorthandForLocal => { | 177 | TextRange::new(reference.range.start(), reference.range.start()) |
172 | mark::hit!(test_rename_local_for_field_shorthand); | 178 | } |
173 | replacement_text.push_str(": "); | 179 | ReferenceKind::FieldShorthandForLocal => { |
174 | replacement_text.push_str(new_name); | 180 | mark::hit!(test_rename_local_for_field_shorthand); |
175 | TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) | 181 | replacement_text.push_str(": "); |
176 | } | 182 | replacement_text.push_str(new_name); |
177 | ReferenceKind::RecordFieldExprOrPat => { | 183 | TextRange::new(reference.range.end(), reference.range.end()) |
178 | mark::hit!(test_rename_field_expr_pat); | 184 | } |
179 | replacement_text.push_str(new_name); | 185 | ReferenceKind::RecordFieldExprOrPat => { |
180 | edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name) | 186 | mark::hit!(test_rename_field_expr_pat); |
181 | } | 187 | replacement_text.push_str(new_name); |
182 | _ => { | 188 | edit_text_range_for_record_field_expr_or_pat( |
183 | replacement_text.push_str(new_name); | 189 | sema, |
184 | reference.file_range.range | 190 | FileRange { file_id, range: reference.range }, |
185 | } | 191 | new_name, |
186 | }; | 192 | ) |
187 | SourceFileEdit { | 193 | } |
188 | file_id: reference.file_range.file_id, | 194 | _ => { |
189 | edit: TextEdit::replace(range, replacement_text), | 195 | replacement_text.push_str(new_name); |
196 | reference.range | ||
197 | } | ||
198 | }; | ||
199 | edit.replace(range, replacement_text); | ||
190 | } | 200 | } |
201 | (file_id, edit.finish()) | ||
191 | } | 202 | } |
192 | 203 | ||
193 | fn edit_text_range_for_record_field_expr_or_pat( | 204 | fn edit_text_range_for_record_field_expr_or_pat( |
@@ -223,9 +234,12 @@ fn rename_mod( | |||
223 | position: FilePosition, | 234 | position: FilePosition, |
224 | module: Module, | 235 | module: Module, |
225 | new_name: &str, | 236 | new_name: &str, |
226 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 237 | ) -> RenameResult<RangeInfo<SourceChange>> { |
227 | let mut source_file_edits = Vec::new(); | 238 | if IdentifierKind::Ident != check_identifier(new_name)? { |
228 | let mut file_system_edits = Vec::new(); | 239 | bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); |
240 | } | ||
241 | |||
242 | let mut source_change = SourceChange::default(); | ||
229 | 243 | ||
230 | let src = module.definition_source(sema.db); | 244 | let src = module.definition_source(sema.db); |
231 | let file_id = src.file_id.original_file(sema.db); | 245 | let file_id = src.file_id.original_file(sema.db); |
@@ -239,7 +253,7 @@ fn rename_mod( | |||
239 | }; | 253 | }; |
240 | let dst = AnchoredPathBuf { anchor: file_id, path }; | 254 | let dst = AnchoredPathBuf { anchor: file_id, path }; |
241 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; | 255 | let move_file = FileSystemEdit::MoveFile { src: file_id, dst }; |
242 | file_system_edits.push(move_file); | 256 | source_change.push_file_system_edit(move_file); |
243 | } | 257 | } |
244 | ModuleSource::Module(..) => {} | 258 | ModuleSource::Module(..) => {} |
245 | } | 259 | } |
@@ -247,22 +261,19 @@ fn rename_mod( | |||
247 | if let Some(src) = module.declaration_source(sema.db) { | 261 | if let Some(src) = module.declaration_source(sema.db) { |
248 | let file_id = src.file_id.original_file(sema.db); | 262 | let file_id = src.file_id.original_file(sema.db); |
249 | let name = src.value.name().unwrap(); | 263 | let name = src.value.name().unwrap(); |
250 | let edit = SourceFileEdit { | 264 | source_change.insert_source_edit( |
251 | file_id, | 265 | file_id, |
252 | edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), | 266 | TextEdit::replace(name.syntax().text_range(), new_name.into()), |
253 | }; | 267 | ); |
254 | source_file_edits.push(edit); | ||
255 | } | 268 | } |
256 | 269 | ||
257 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) | 270 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
258 | .ok_or_else(|| RenameError("No references found at position".to_string()))?; | 271 | let ref_edits = refs.references().iter().map(|(&file_id, references)| { |
259 | let ref_edits = refs | 272 | source_edit_from_references(sema, file_id, references, new_name) |
260 | .references | 273 | }); |
261 | .into_iter() | 274 | source_change.extend(ref_edits); |
262 | .map(|reference| source_edit_from_reference(sema, reference, new_name)); | ||
263 | source_file_edits.extend(ref_edits); | ||
264 | 275 | ||
265 | Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) | 276 | Ok(RangeInfo::new(range, source_change)) |
266 | } | 277 | } |
267 | 278 | ||
268 | fn rename_to_self( | 279 | fn rename_to_self( |
@@ -274,27 +285,26 @@ fn rename_to_self( | |||
274 | 285 | ||
275 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) | 286 | let (fn_def, fn_ast) = find_node_at_offset::<ast::Fn>(syn, position.offset) |
276 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) | 287 | .and_then(|fn_ast| sema.to_def(&fn_ast).zip(Some(fn_ast))) |
277 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | 288 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; |
278 | let param_range = fn_ast | 289 | let param_range = fn_ast |
279 | .param_list() | 290 | .param_list() |
280 | .and_then(|p| p.params().next()) | 291 | .and_then(|p| p.params().next()) |
281 | .ok_or_else(|| RenameError("Method has no parameters".to_string()))? | 292 | .ok_or_else(|| format_err!("Method has no parameters"))? |
282 | .syntax() | 293 | .syntax() |
283 | .text_range(); | 294 | .text_range(); |
284 | if !param_range.contains(position.offset) { | 295 | if !param_range.contains(position.offset) { |
285 | return Err(RenameError("Only the first parameter can be self".to_string())); | 296 | bail!("Only the first parameter can be self"); |
286 | } | 297 | } |
287 | 298 | ||
288 | let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) | 299 | let impl_block = find_node_at_offset::<ast::Impl>(syn, position.offset) |
289 | .and_then(|def| sema.to_def(&def)) | 300 | .and_then(|def| sema.to_def(&def)) |
290 | .ok_or_else(|| RenameError("No impl block found for function".to_string()))?; | 301 | .ok_or_else(|| format_err!("No impl block found for function"))?; |
291 | if fn_def.self_param(sema.db).is_some() { | 302 | if fn_def.self_param(sema.db).is_some() { |
292 | return Err(RenameError("Method already has a self parameter".to_string())); | 303 | bail!("Method already has a self parameter"); |
293 | } | 304 | } |
294 | 305 | ||
295 | let params = fn_def.assoc_fn_params(sema.db); | 306 | let params = fn_def.assoc_fn_params(sema.db); |
296 | let first_param = | 307 | let first_param = params.first().ok_or_else(|| format_err!("Method has no parameters"))?; |
297 | params.first().ok_or_else(|| RenameError("Method has no parameters".into()))?; | ||
298 | let first_param_ty = first_param.ty(); | 308 | let first_param_ty = first_param.ty(); |
299 | let impl_ty = impl_block.target_ty(sema.db); | 309 | let impl_ty = impl_block.target_ty(sema.db); |
300 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { | 310 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { |
@@ -307,31 +317,21 @@ fn rename_to_self( | |||
307 | }; | 317 | }; |
308 | 318 | ||
309 | if ty != impl_ty { | 319 | if ty != impl_ty { |
310 | return Err(RenameError("Parameter type differs from impl block type".to_string())); | 320 | bail!("Parameter type differs from impl block type"); |
311 | } | ||
312 | |||
313 | let RangeInfo { range, info: refs } = find_all_refs(sema, position, None) | ||
314 | .ok_or_else(|| RenameError("No reference found at position".to_string()))?; | ||
315 | |||
316 | let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs | ||
317 | .into_iter() | ||
318 | .partition(|reference| param_range.intersect(reference.file_range.range).is_some()); | ||
319 | |||
320 | if param_ref.is_empty() { | ||
321 | return Err(RenameError("Parameter to rename not found".to_string())); | ||
322 | } | 321 | } |
323 | 322 | ||
324 | let mut edits = usages | 323 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
325 | .into_iter() | ||
326 | .map(|reference| source_edit_from_reference(sema, reference, "self")) | ||
327 | .collect::<Vec<_>>(); | ||
328 | 324 | ||
329 | edits.push(SourceFileEdit { | 325 | let mut source_change = SourceChange::default(); |
330 | file_id: position.file_id, | 326 | source_change.extend(refs.references().iter().map(|(&file_id, references)| { |
331 | edit: TextEdit::replace(param_range, String::from(self_param)), | 327 | source_edit_from_references(sema, file_id, references, "self") |
332 | }); | 328 | })); |
329 | source_change.insert_source_edit( | ||
330 | position.file_id, | ||
331 | TextEdit::replace(param_range, String::from(self_param)), | ||
332 | ); | ||
333 | 333 | ||
334 | Ok(RangeInfo::new(range, SourceChange::from(edits))) | 334 | Ok(RangeInfo::new(range, source_change)) |
335 | } | 335 | } |
336 | 336 | ||
337 | fn text_edit_from_self_param( | 337 | fn text_edit_from_self_param( |
@@ -364,77 +364,93 @@ fn text_edit_from_self_param( | |||
364 | fn rename_self_to_param( | 364 | fn rename_self_to_param( |
365 | sema: &Semantics<RootDatabase>, | 365 | sema: &Semantics<RootDatabase>, |
366 | position: FilePosition, | 366 | position: FilePosition, |
367 | self_token: SyntaxToken, | ||
368 | new_name: &str, | 367 | new_name: &str, |
368 | ident_kind: IdentifierKind, | ||
369 | range: TextRange, | ||
370 | refs: ReferenceSearchResult, | ||
369 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 371 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
372 | match ident_kind { | ||
373 | IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name), | ||
374 | IdentifierKind::ToSelf => { | ||
375 | // no-op | ||
376 | mark::hit!(rename_self_to_self); | ||
377 | return Ok(RangeInfo::new(range, SourceChange::default())); | ||
378 | } | ||
379 | _ => (), | ||
380 | } | ||
370 | let source_file = sema.parse(position.file_id); | 381 | let source_file = sema.parse(position.file_id); |
371 | let syn = source_file.syntax(); | 382 | let syn = source_file.syntax(); |
372 | 383 | ||
373 | let text = sema.db.file_text(position.file_id); | ||
374 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) | 384 | let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset) |
375 | .ok_or_else(|| RenameError("No surrounding method declaration found".to_string()))?; | 385 | .ok_or_else(|| format_err!("No surrounding method declaration found"))?; |
376 | let search_range = fn_def.syntax().text_range(); | 386 | |
387 | let mut source_change = SourceChange::default(); | ||
388 | if let Some(self_param) = fn_def.param_list().and_then(|it| it.self_param()) { | ||
389 | if self_param | ||
390 | .syntax() | ||
391 | .text_range() | ||
392 | .contains_range(refs.declaration().nav.focus_or_full_range()) | ||
393 | { | ||
394 | let edit = text_edit_from_self_param(syn, &self_param, new_name) | ||
395 | .ok_or_else(|| format_err!("No target type found"))?; | ||
396 | source_change.insert_source_edit(position.file_id, edit); | ||
377 | 397 | ||
378 | let mut edits: Vec<SourceFileEdit> = vec![]; | 398 | source_change.extend(refs.references().iter().map(|(&file_id, references)| { |
399 | source_edit_from_references(sema, file_id, &references, new_name) | ||
400 | })); | ||
379 | 401 | ||
380 | for (idx, _) in text.match_indices("self") { | 402 | if source_change.source_file_edits.len() > 1 && ident_kind == IdentifierKind::Underscore |
381 | let offset: TextSize = idx.try_into().unwrap(); | 403 | { |
382 | if !search_range.contains_inclusive(offset) { | 404 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); |
383 | continue; | 405 | } |
384 | } | 406 | |
385 | if let Some(ref usage) = | 407 | return Ok(RangeInfo::new(range, source_change)); |
386 | syn.token_at_offset(offset).find(|t| t.kind() == SyntaxKind::SELF_KW) | ||
387 | { | ||
388 | let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { | ||
389 | text_edit_from_self_param(syn, self_param, new_name) | ||
390 | .ok_or_else(|| RenameError("No target type found".to_string()))? | ||
391 | } else { | ||
392 | TextEdit::replace(usage.text_range(), String::from(new_name)) | ||
393 | }; | ||
394 | edits.push(SourceFileEdit { file_id: position.file_id, edit }); | ||
395 | } | 408 | } |
396 | } | 409 | } |
397 | 410 | Err(format_err!("Method has no self param")) | |
398 | let range = ast::SelfParam::cast(self_token.parent()) | ||
399 | .map_or(self_token.text_range(), |p| p.syntax().text_range()); | ||
400 | |||
401 | Ok(RangeInfo::new(range, SourceChange::from(edits))) | ||
402 | } | 411 | } |
403 | 412 | ||
404 | fn rename_reference( | 413 | fn rename_reference( |
405 | sema: &Semantics<RootDatabase>, | 414 | sema: &Semantics<RootDatabase>, |
406 | position: FilePosition, | 415 | position: FilePosition, |
407 | new_name: &str, | 416 | new_name: &str, |
408 | is_lifetime_name: bool, | ||
409 | ) -> Result<RangeInfo<SourceChange>, RenameError> { | 417 | ) -> Result<RangeInfo<SourceChange>, RenameError> { |
410 | let RangeInfo { range, info: refs } = match find_all_refs(sema, position, None) { | 418 | let ident_kind = check_identifier(new_name)?; |
411 | Some(range_info) => range_info, | 419 | let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; |
412 | None => return Err(RenameError("No references found at position".to_string())), | 420 | |
413 | }; | 421 | match (ident_kind, &refs.declaration.kind) { |
414 | 422 | (IdentifierKind::ToSelf, ReferenceKind::Lifetime) | |
415 | match (refs.declaration.kind == ReferenceKind::Lifetime, is_lifetime_name) { | 423 | | (IdentifierKind::Underscore, ReferenceKind::Lifetime) |
416 | (true, false) => { | 424 | | (IdentifierKind::Ident, ReferenceKind::Lifetime) => { |
417 | return Err(RenameError(format!( | 425 | mark::hit!(rename_not_a_lifetime_ident_ref); |
418 | "Invalid name `{}`: not a lifetime identifier", | 426 | bail!("Invalid name `{}`: not a lifetime identifier", new_name) |
419 | new_name | ||
420 | ))) | ||
421 | } | 427 | } |
422 | (false, true) => { | 428 | (IdentifierKind::Lifetime, ReferenceKind::Lifetime) => mark::hit!(rename_lifetime), |
423 | return Err(RenameError(format!("Invalid name `{}`: not an identifier", new_name))) | 429 | (IdentifierKind::Lifetime, _) => { |
430 | mark::hit!(rename_not_an_ident_ref); | ||
431 | bail!("Invalid name `{}`: not an identifier", new_name) | ||
424 | } | 432 | } |
425 | _ => (), | 433 | (_, ReferenceKind::SelfParam) => { |
434 | mark::hit!(rename_self_to_param); | ||
435 | return rename_self_to_param(sema, position, new_name, ident_kind, range, refs); | ||
436 | } | ||
437 | (IdentifierKind::ToSelf, _) => { | ||
438 | mark::hit!(rename_to_self); | ||
439 | return rename_to_self(sema, position); | ||
440 | } | ||
441 | (IdentifierKind::Underscore, _) if !refs.references.is_empty() => { | ||
442 | mark::hit!(rename_underscore_multiple); | ||
443 | bail!("Cannot rename reference to `_` as it is being referenced multiple times") | ||
444 | } | ||
445 | (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident), | ||
426 | } | 446 | } |
427 | 447 | ||
428 | let edit = refs | 448 | let mut source_change = SourceChange::default(); |
429 | .into_iter() | 449 | source_change.extend(refs.into_iter().map(|(file_id, references)| { |
430 | .map(|reference| source_edit_from_reference(sema, reference, new_name)) | 450 | source_edit_from_references(sema, file_id, &references, new_name) |
431 | .collect::<Vec<_>>(); | 451 | })); |
432 | |||
433 | if edit.is_empty() { | ||
434 | return Err(RenameError("No references found at position".to_string())); | ||
435 | } | ||
436 | 452 | ||
437 | Ok(RangeInfo::new(range, SourceChange::from(edit))) | 453 | Ok(RangeInfo::new(range, source_change)) |
438 | } | 454 | } |
439 | 455 | ||
440 | #[cfg(test)] | 456 | #[cfg(test)] |
@@ -457,14 +473,16 @@ mod tests { | |||
457 | let mut text_edit_builder = TextEdit::builder(); | 473 | let mut text_edit_builder = TextEdit::builder(); |
458 | let mut file_id: Option<FileId> = None; | 474 | let mut file_id: Option<FileId> = None; |
459 | for edit in source_change.info.source_file_edits { | 475 | for edit in source_change.info.source_file_edits { |
460 | file_id = Some(edit.file_id); | 476 | file_id = Some(edit.0); |
461 | for indel in edit.edit.into_iter() { | 477 | for indel in edit.1.into_iter() { |
462 | text_edit_builder.replace(indel.delete, indel.insert); | 478 | text_edit_builder.replace(indel.delete, indel.insert); |
463 | } | 479 | } |
464 | } | 480 | } |
465 | let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string(); | 481 | if let Some(file_id) = file_id { |
466 | text_edit_builder.finish().apply(&mut result); | 482 | let mut result = analysis.file_text(file_id).unwrap().to_string(); |
467 | assert_eq_text!(ra_fixture_after, &*result); | 483 | text_edit_builder.finish().apply(&mut result); |
484 | assert_eq_text!(ra_fixture_after, &*result); | ||
485 | } | ||
468 | } | 486 | } |
469 | Err(err) => { | 487 | Err(err) => { |
470 | if ra_fixture_after.starts_with("error:") { | 488 | if ra_fixture_after.starts_with("error:") { |
@@ -493,19 +511,19 @@ mod tests { | |||
493 | 511 | ||
494 | #[test] | 512 | #[test] |
495 | fn test_rename_to_underscore() { | 513 | fn test_rename_to_underscore() { |
496 | check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#); | 514 | check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); |
497 | } | 515 | } |
498 | 516 | ||
499 | #[test] | 517 | #[test] |
500 | fn test_rename_to_raw_identifier() { | 518 | fn test_rename_to_raw_identifier() { |
501 | check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#); | 519 | check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#); |
502 | } | 520 | } |
503 | 521 | ||
504 | #[test] | 522 | #[test] |
505 | fn test_rename_to_invalid_identifier1() { | 523 | fn test_rename_to_invalid_identifier1() { |
506 | check( | 524 | check( |
507 | "invalid!", | 525 | "invalid!", |
508 | r#"fn main() { let i<|> = 1; }"#, | 526 | r#"fn main() { let i$0 = 1; }"#, |
509 | "error: Invalid name `invalid!`: not an identifier", | 527 | "error: Invalid name `invalid!`: not an identifier", |
510 | ); | 528 | ); |
511 | } | 529 | } |
@@ -514,7 +532,7 @@ mod tests { | |||
514 | fn test_rename_to_invalid_identifier2() { | 532 | fn test_rename_to_invalid_identifier2() { |
515 | check( | 533 | check( |
516 | "multiple tokens", | 534 | "multiple tokens", |
517 | r#"fn main() { let i<|> = 1; }"#, | 535 | r#"fn main() { let i$0 = 1; }"#, |
518 | "error: Invalid name `multiple tokens`: not an identifier", | 536 | "error: Invalid name `multiple tokens`: not an identifier", |
519 | ); | 537 | ); |
520 | } | 538 | } |
@@ -523,38 +541,60 @@ mod tests { | |||
523 | fn test_rename_to_invalid_identifier3() { | 541 | fn test_rename_to_invalid_identifier3() { |
524 | check( | 542 | check( |
525 | "let", | 543 | "let", |
526 | r#"fn main() { let i<|> = 1; }"#, | 544 | r#"fn main() { let i$0 = 1; }"#, |
527 | "error: Invalid name `let`: not an identifier", | 545 | "error: Invalid name `let`: not an identifier", |
528 | ); | 546 | ); |
529 | } | 547 | } |
530 | 548 | ||
531 | #[test] | 549 | #[test] |
532 | fn test_rename_to_invalid_identifier_lifetime() { | 550 | fn test_rename_to_invalid_identifier_lifetime() { |
551 | mark::check!(rename_not_an_ident_ref); | ||
533 | check( | 552 | check( |
534 | "'foo", | 553 | "'foo", |
535 | r#"fn main() { let i<|> = 1; }"#, | 554 | r#"fn main() { let i$0 = 1; }"#, |
536 | "error: Invalid name `'foo`: not an identifier", | 555 | "error: Invalid name `'foo`: not an identifier", |
537 | ); | 556 | ); |
538 | } | 557 | } |
539 | 558 | ||
540 | #[test] | 559 | #[test] |
541 | fn test_rename_to_invalid_identifier_lifetime2() { | 560 | fn test_rename_to_invalid_identifier_lifetime2() { |
561 | mark::check!(rename_not_a_lifetime_ident_ref); | ||
542 | check( | 562 | check( |
543 | "foo", | 563 | "foo", |
544 | r#"fn main<'a>(_: &'a<|> ()) {}"#, | 564 | r#"fn main<'a>(_: &'a$0 ()) {}"#, |
545 | "error: Invalid name `foo`: not a lifetime identifier", | 565 | "error: Invalid name `foo`: not a lifetime identifier", |
546 | ); | 566 | ); |
547 | } | 567 | } |
548 | 568 | ||
549 | #[test] | 569 | #[test] |
570 | fn test_rename_to_underscore_invalid() { | ||
571 | mark::check!(rename_underscore_multiple); | ||
572 | check( | ||
573 | "_", | ||
574 | r#"fn main(foo$0: ()) {foo;}"#, | ||
575 | "error: Cannot rename reference to `_` as it is being referenced multiple times", | ||
576 | ); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn test_rename_mod_invalid() { | ||
581 | check( | ||
582 | "'foo", | ||
583 | r#"mod foo$0 {}"#, | ||
584 | "error: Invalid name `'foo`: cannot rename module to 'foo", | ||
585 | ); | ||
586 | } | ||
587 | |||
588 | #[test] | ||
550 | fn test_rename_for_local() { | 589 | fn test_rename_for_local() { |
590 | mark::check!(rename_ident); | ||
551 | check( | 591 | check( |
552 | "k", | 592 | "k", |
553 | r#" | 593 | r#" |
554 | fn main() { | 594 | fn main() { |
555 | let mut i = 1; | 595 | let mut i = 1; |
556 | let j = 1; | 596 | let j = 1; |
557 | i = i<|> + j; | 597 | i = i$0 + j; |
558 | 598 | ||
559 | { i = 0; } | 599 | { i = 0; } |
560 | 600 | ||
@@ -579,7 +619,7 @@ fn main() { | |||
579 | fn test_rename_unresolved_reference() { | 619 | fn test_rename_unresolved_reference() { |
580 | check( | 620 | check( |
581 | "new_name", | 621 | "new_name", |
582 | r#"fn main() { let _ = unresolved_ref<|>; }"#, | 622 | r#"fn main() { let _ = unresolved_ref$0; }"#, |
583 | "error: No references found at position", | 623 | "error: No references found at position", |
584 | ); | 624 | ); |
585 | } | 625 | } |
@@ -591,7 +631,7 @@ fn main() { | |||
591 | r#" | 631 | r#" |
592 | macro_rules! foo {($i:ident) => {$i} } | 632 | macro_rules! foo {($i:ident) => {$i} } |
593 | fn main() { | 633 | fn main() { |
594 | let a<|> = "test"; | 634 | let a$0 = "test"; |
595 | foo!(a); | 635 | foo!(a); |
596 | } | 636 | } |
597 | "#, | 637 | "#, |
@@ -613,7 +653,7 @@ fn main() { | |||
613 | macro_rules! foo {($i:ident) => {$i} } | 653 | macro_rules! foo {($i:ident) => {$i} } |
614 | fn main() { | 654 | fn main() { |
615 | let a = "test"; | 655 | let a = "test"; |
616 | foo!(a<|>); | 656 | foo!(a$0); |
617 | } | 657 | } |
618 | "#, | 658 | "#, |
619 | r#" | 659 | r#" |
@@ -634,7 +674,7 @@ fn main() { | |||
634 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | 674 | macro_rules! define_fn {($id:ident) => { fn $id{} }} |
635 | define_fn!(foo); | 675 | define_fn!(foo); |
636 | fn main() { | 676 | fn main() { |
637 | fo<|>o(); | 677 | fo$0o(); |
638 | } | 678 | } |
639 | "#, | 679 | "#, |
640 | r#" | 680 | r#" |
@@ -653,7 +693,7 @@ fn main() { | |||
653 | "bar", | 693 | "bar", |
654 | r#" | 694 | r#" |
655 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | 695 | macro_rules! define_fn {($id:ident) => { fn $id{} }} |
656 | define_fn!(fo<|>o); | 696 | define_fn!(fo$0o); |
657 | fn main() { | 697 | fn main() { |
658 | foo(); | 698 | foo(); |
659 | } | 699 | } |
@@ -670,17 +710,17 @@ fn main() { | |||
670 | 710 | ||
671 | #[test] | 711 | #[test] |
672 | fn test_rename_for_param_inside() { | 712 | fn test_rename_for_param_inside() { |
673 | check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#); | 713 | check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#); |
674 | } | 714 | } |
675 | 715 | ||
676 | #[test] | 716 | #[test] |
677 | fn test_rename_refs_for_fn_param() { | 717 | fn test_rename_refs_for_fn_param() { |
678 | check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); | 718 | check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); |
679 | } | 719 | } |
680 | 720 | ||
681 | #[test] | 721 | #[test] |
682 | fn test_rename_for_mut_param() { | 722 | fn test_rename_for_mut_param() { |
683 | check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); | 723 | check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); |
684 | } | 724 | } |
685 | 725 | ||
686 | #[test] | 726 | #[test] |
@@ -688,7 +728,7 @@ fn main() { | |||
688 | check( | 728 | check( |
689 | "j", | 729 | "j", |
690 | r#" | 730 | r#" |
691 | struct Foo { i<|>: i32 } | 731 | struct Foo { i$0: i32 } |
692 | 732 | ||
693 | impl Foo { | 733 | impl Foo { |
694 | fn new(i: i32) -> Self { | 734 | fn new(i: i32) -> Self { |
@@ -714,7 +754,7 @@ impl Foo { | |||
714 | check( | 754 | check( |
715 | "j", | 755 | "j", |
716 | r#" | 756 | r#" |
717 | struct Foo { i<|>: i32 } | 757 | struct Foo { i$0: i32 } |
718 | 758 | ||
719 | impl Foo { | 759 | impl Foo { |
720 | fn new(i: i32) -> Self { | 760 | fn new(i: i32) -> Self { |
@@ -743,7 +783,7 @@ impl Foo { | |||
743 | struct Foo { i: i32 } | 783 | struct Foo { i: i32 } |
744 | 784 | ||
745 | impl Foo { | 785 | impl Foo { |
746 | fn new(i<|>: i32) -> Self { | 786 | fn new(i$0: i32) -> Self { |
747 | Self { i } | 787 | Self { i } |
748 | } | 788 | } |
749 | } | 789 | } |
@@ -765,7 +805,7 @@ impl Foo { | |||
765 | check( | 805 | check( |
766 | "j", | 806 | "j", |
767 | r#" | 807 | r#" |
768 | struct Foo { i<|>: i32 } | 808 | struct Foo { i$0: i32 } |
769 | struct Bar { i: i32 } | 809 | struct Bar { i: i32 } |
770 | 810 | ||
771 | impl Bar { | 811 | impl Bar { |
@@ -794,7 +834,7 @@ impl Bar { | |||
794 | r#" | 834 | r#" |
795 | struct Foo { i: i32 } | 835 | struct Foo { i: i32 } |
796 | 836 | ||
797 | fn baz(i<|>: i32) -> Self { | 837 | fn baz(i$0: i32) -> Self { |
798 | let x = Foo { i }; | 838 | let x = Foo { i }; |
799 | { | 839 | { |
800 | let i = 0; | 840 | let i = 0; |
@@ -825,7 +865,7 @@ fn baz(j: i32) -> Self { | |||
825 | mod bar; | 865 | mod bar; |
826 | 866 | ||
827 | //- /bar.rs | 867 | //- /bar.rs |
828 | mod foo<|>; | 868 | mod foo$0; |
829 | 869 | ||
830 | //- /bar/foo.rs | 870 | //- /bar/foo.rs |
831 | // empty | 871 | // empty |
@@ -834,21 +874,18 @@ mod foo<|>; | |||
834 | RangeInfo { | 874 | RangeInfo { |
835 | range: 4..7, | 875 | range: 4..7, |
836 | info: SourceChange { | 876 | info: SourceChange { |
837 | source_file_edits: [ | 877 | source_file_edits: { |
838 | SourceFileEdit { | 878 | FileId( |
839 | file_id: FileId( | 879 | 1, |
840 | 1, | 880 | ): TextEdit { |
841 | ), | 881 | indels: [ |
842 | edit: TextEdit { | 882 | Indel { |
843 | indels: [ | 883 | insert: "foo2", |
844 | Indel { | 884 | delete: 4..7, |
845 | insert: "foo2", | 885 | }, |
846 | delete: 4..7, | 886 | ], |
847 | }, | ||
848 | ], | ||
849 | }, | ||
850 | }, | 887 | }, |
851 | ], | 888 | }, |
852 | file_system_edits: [ | 889 | file_system_edits: [ |
853 | MoveFile { | 890 | MoveFile { |
854 | src: FileId( | 891 | src: FileId( |
@@ -883,40 +920,34 @@ fn main() {} | |||
883 | pub struct FooContent; | 920 | pub struct FooContent; |
884 | 921 | ||
885 | //- /bar.rs | 922 | //- /bar.rs |
886 | use crate::foo<|>::FooContent; | 923 | use crate::foo$0::FooContent; |
887 | "#, | 924 | "#, |
888 | expect![[r#" | 925 | expect![[r#" |
889 | RangeInfo { | 926 | RangeInfo { |
890 | range: 11..14, | 927 | range: 11..14, |
891 | info: SourceChange { | 928 | info: SourceChange { |
892 | source_file_edits: [ | 929 | source_file_edits: { |
893 | SourceFileEdit { | 930 | FileId( |
894 | file_id: FileId( | 931 | 0, |
895 | 0, | 932 | ): TextEdit { |
896 | ), | 933 | indels: [ |
897 | edit: TextEdit { | 934 | Indel { |
898 | indels: [ | 935 | insert: "quux", |
899 | Indel { | 936 | delete: 8..11, |
900 | insert: "quux", | 937 | }, |
901 | delete: 8..11, | 938 | ], |
902 | }, | ||
903 | ], | ||
904 | }, | ||
905 | }, | 939 | }, |
906 | SourceFileEdit { | 940 | FileId( |
907 | file_id: FileId( | 941 | 2, |
908 | 2, | 942 | ): TextEdit { |
909 | ), | 943 | indels: [ |
910 | edit: TextEdit { | 944 | Indel { |
911 | indels: [ | 945 | insert: "quux", |
912 | Indel { | 946 | delete: 11..14, |
913 | insert: "quux", | 947 | }, |
914 | delete: 11..14, | 948 | ], |
915 | }, | ||
916 | ], | ||
917 | }, | ||
918 | }, | 949 | }, |
919 | ], | 950 | }, |
920 | file_system_edits: [ | 951 | file_system_edits: [ |
921 | MoveFile { | 952 | MoveFile { |
922 | src: FileId( | 953 | src: FileId( |
@@ -943,29 +974,26 @@ use crate::foo<|>::FooContent; | |||
943 | "foo2", | 974 | "foo2", |
944 | r#" | 975 | r#" |
945 | //- /lib.rs | 976 | //- /lib.rs |
946 | mod fo<|>o; | 977 | mod fo$0o; |
947 | //- /foo/mod.rs | 978 | //- /foo/mod.rs |
948 | // emtpy | 979 | // empty |
949 | "#, | 980 | "#, |
950 | expect![[r#" | 981 | expect![[r#" |
951 | RangeInfo { | 982 | RangeInfo { |
952 | range: 4..7, | 983 | range: 4..7, |
953 | info: SourceChange { | 984 | info: SourceChange { |
954 | source_file_edits: [ | 985 | source_file_edits: { |
955 | SourceFileEdit { | 986 | FileId( |
956 | file_id: FileId( | 987 | 0, |
957 | 0, | 988 | ): TextEdit { |
958 | ), | 989 | indels: [ |
959 | edit: TextEdit { | 990 | Indel { |
960 | indels: [ | 991 | insert: "foo2", |
961 | Indel { | 992 | delete: 4..7, |
962 | insert: "foo2", | 993 | }, |
963 | delete: 4..7, | 994 | ], |
964 | }, | ||
965 | ], | ||
966 | }, | ||
967 | }, | 995 | }, |
968 | ], | 996 | }, |
969 | file_system_edits: [ | 997 | file_system_edits: [ |
970 | MoveFile { | 998 | MoveFile { |
971 | src: FileId( | 999 | src: FileId( |
@@ -992,30 +1020,27 @@ mod fo<|>o; | |||
992 | "bar", | 1020 | "bar", |
993 | r#" | 1021 | r#" |
994 | //- /lib.rs | 1022 | //- /lib.rs |
995 | mod outer { mod fo<|>o; } | 1023 | mod outer { mod fo$0o; } |
996 | 1024 | ||
997 | //- /outer/foo.rs | 1025 | //- /outer/foo.rs |
998 | // emtpy | 1026 | // empty |
999 | "#, | 1027 | "#, |
1000 | expect![[r#" | 1028 | expect![[r#" |
1001 | RangeInfo { | 1029 | RangeInfo { |
1002 | range: 16..19, | 1030 | range: 16..19, |
1003 | info: SourceChange { | 1031 | info: SourceChange { |
1004 | source_file_edits: [ | 1032 | source_file_edits: { |
1005 | SourceFileEdit { | 1033 | FileId( |
1006 | file_id: FileId( | 1034 | 0, |
1007 | 0, | 1035 | ): TextEdit { |
1008 | ), | 1036 | indels: [ |
1009 | edit: TextEdit { | 1037 | Indel { |
1010 | indels: [ | 1038 | insert: "bar", |
1011 | Indel { | 1039 | delete: 16..19, |
1012 | insert: "bar", | 1040 | }, |
1013 | delete: 16..19, | 1041 | ], |
1014 | }, | ||
1015 | ], | ||
1016 | }, | ||
1017 | }, | 1042 | }, |
1018 | ], | 1043 | }, |
1019 | file_system_edits: [ | 1044 | file_system_edits: [ |
1020 | MoveFile { | 1045 | MoveFile { |
1021 | src: FileId( | 1046 | src: FileId( |
@@ -1041,7 +1066,7 @@ mod outer { mod fo<|>o; } | |||
1041 | check( | 1066 | check( |
1042 | "baz", | 1067 | "baz", |
1043 | r#" | 1068 | r#" |
1044 | mod <|>foo { pub fn bar() {} } | 1069 | mod $0foo { pub fn bar() {} } |
1045 | 1070 | ||
1046 | fn main() { foo::bar(); } | 1071 | fn main() { foo::bar(); } |
1047 | "#, | 1072 | "#, |
@@ -1065,7 +1090,7 @@ fn f() { | |||
1065 | } | 1090 | } |
1066 | 1091 | ||
1067 | //- /bar.rs | 1092 | //- /bar.rs |
1068 | pub mod foo<|>; | 1093 | pub mod foo$0; |
1069 | 1094 | ||
1070 | //- /bar/foo.rs | 1095 | //- /bar/foo.rs |
1071 | // pub fn fun() {} | 1096 | // pub fn fun() {} |
@@ -1074,34 +1099,28 @@ pub mod foo<|>; | |||
1074 | RangeInfo { | 1099 | RangeInfo { |
1075 | range: 8..11, | 1100 | range: 8..11, |
1076 | info: SourceChange { | 1101 | info: SourceChange { |
1077 | source_file_edits: [ | 1102 | source_file_edits: { |
1078 | SourceFileEdit { | 1103 | FileId( |
1079 | file_id: FileId( | 1104 | 0, |
1080 | 1, | 1105 | ): TextEdit { |
1081 | ), | 1106 | indels: [ |
1082 | edit: TextEdit { | 1107 | Indel { |
1083 | indels: [ | 1108 | insert: "foo2", |
1084 | Indel { | 1109 | delete: 27..30, |
1085 | insert: "foo2", | 1110 | }, |
1086 | delete: 8..11, | 1111 | ], |
1087 | }, | ||
1088 | ], | ||
1089 | }, | ||
1090 | }, | 1112 | }, |
1091 | SourceFileEdit { | 1113 | FileId( |
1092 | file_id: FileId( | 1114 | 1, |
1093 | 0, | 1115 | ): TextEdit { |
1094 | ), | 1116 | indels: [ |
1095 | edit: TextEdit { | 1117 | Indel { |
1096 | indels: [ | 1118 | insert: "foo2", |
1097 | Indel { | 1119 | delete: 8..11, |
1098 | insert: "foo2", | 1120 | }, |
1099 | delete: 27..30, | 1121 | ], |
1100 | }, | ||
1101 | ], | ||
1102 | }, | ||
1103 | }, | 1122 | }, |
1104 | ], | 1123 | }, |
1105 | file_system_edits: [ | 1124 | file_system_edits: [ |
1106 | MoveFile { | 1125 | MoveFile { |
1107 | src: FileId( | 1126 | src: FileId( |
@@ -1128,7 +1147,7 @@ pub mod foo<|>; | |||
1128 | "Baz", | 1147 | "Baz", |
1129 | r#" | 1148 | r#" |
1130 | mod foo { | 1149 | mod foo { |
1131 | pub enum Foo { Bar<|> } | 1150 | pub enum Foo { Bar$0 } |
1132 | } | 1151 | } |
1133 | 1152 | ||
1134 | fn func(f: foo::Foo) { | 1153 | fn func(f: foo::Foo) { |
@@ -1157,7 +1176,7 @@ fn func(f: foo::Foo) { | |||
1157 | "baz", | 1176 | "baz", |
1158 | r#" | 1177 | r#" |
1159 | mod foo { | 1178 | mod foo { |
1160 | pub struct Foo { pub bar<|>: uint } | 1179 | pub struct Foo { pub bar$0: uint } |
1161 | } | 1180 | } |
1162 | 1181 | ||
1163 | fn foo(f: foo::Foo) { | 1182 | fn foo(f: foo::Foo) { |
@@ -1178,13 +1197,14 @@ fn foo(f: foo::Foo) { | |||
1178 | 1197 | ||
1179 | #[test] | 1198 | #[test] |
1180 | fn test_parameter_to_self() { | 1199 | fn test_parameter_to_self() { |
1200 | mark::check!(rename_to_self); | ||
1181 | check( | 1201 | check( |
1182 | "self", | 1202 | "self", |
1183 | r#" | 1203 | r#" |
1184 | struct Foo { i: i32 } | 1204 | struct Foo { i: i32 } |
1185 | 1205 | ||
1186 | impl Foo { | 1206 | impl Foo { |
1187 | fn f(foo<|>: &mut Foo) -> i32 { | 1207 | fn f(foo$0: &mut Foo) -> i32 { |
1188 | foo.i | 1208 | foo.i |
1189 | } | 1209 | } |
1190 | } | 1210 | } |
@@ -1205,7 +1225,7 @@ impl Foo { | |||
1205 | struct Foo { i: i32 } | 1225 | struct Foo { i: i32 } |
1206 | 1226 | ||
1207 | impl Foo { | 1227 | impl Foo { |
1208 | fn f(foo<|>: Foo) -> i32 { | 1228 | fn f(foo$0: Foo) -> i32 { |
1209 | foo.i | 1229 | foo.i |
1210 | } | 1230 | } |
1211 | } | 1231 | } |
@@ -1229,7 +1249,7 @@ impl Foo { | |||
1229 | r#" | 1249 | r#" |
1230 | struct Foo { i: i32 } | 1250 | struct Foo { i: i32 } |
1231 | 1251 | ||
1232 | fn f(foo<|>: &mut Foo) -> i32 { | 1252 | fn f(foo$0: &mut Foo) -> i32 { |
1233 | foo.i | 1253 | foo.i |
1234 | } | 1254 | } |
1235 | "#, | 1255 | "#, |
@@ -1242,7 +1262,7 @@ struct Foo { i: i32 } | |||
1242 | struct Bar; | 1262 | struct Bar; |
1243 | 1263 | ||
1244 | impl Bar { | 1264 | impl Bar { |
1245 | fn f(foo<|>: &mut Foo) -> i32 { | 1265 | fn f(foo$0: &mut Foo) -> i32 { |
1246 | foo.i | 1266 | foo.i |
1247 | } | 1267 | } |
1248 | } | 1268 | } |
@@ -1258,7 +1278,7 @@ impl Bar { | |||
1258 | r#" | 1278 | r#" |
1259 | struct Foo { i: i32 } | 1279 | struct Foo { i: i32 } |
1260 | impl Foo { | 1280 | impl Foo { |
1261 | fn f(x: (), foo<|>: &mut Foo) -> i32 { | 1281 | fn f(x: (), foo$0: &mut Foo) -> i32 { |
1262 | foo.i | 1282 | foo.i |
1263 | } | 1283 | } |
1264 | } | 1284 | } |
@@ -1274,7 +1294,7 @@ impl Foo { | |||
1274 | r#" | 1294 | r#" |
1275 | struct Foo { i: i32 } | 1295 | struct Foo { i: i32 } |
1276 | impl &Foo { | 1296 | impl &Foo { |
1277 | fn f(foo<|>: &Foo) -> i32 { | 1297 | fn f(foo$0: &Foo) -> i32 { |
1278 | foo.i | 1298 | foo.i |
1279 | } | 1299 | } |
1280 | } | 1300 | } |
@@ -1298,7 +1318,7 @@ impl &Foo { | |||
1298 | struct Foo { i: i32 } | 1318 | struct Foo { i: i32 } |
1299 | 1319 | ||
1300 | impl Foo { | 1320 | impl Foo { |
1301 | fn f(&mut <|>self) -> i32 { | 1321 | fn f(&mut $0self) -> i32 { |
1302 | self.i | 1322 | self.i |
1303 | } | 1323 | } |
1304 | } | 1324 | } |
@@ -1317,13 +1337,14 @@ impl Foo { | |||
1317 | 1337 | ||
1318 | #[test] | 1338 | #[test] |
1319 | fn test_owned_self_to_parameter() { | 1339 | fn test_owned_self_to_parameter() { |
1340 | mark::check!(rename_self_to_param); | ||
1320 | check( | 1341 | check( |
1321 | "foo", | 1342 | "foo", |
1322 | r#" | 1343 | r#" |
1323 | struct Foo { i: i32 } | 1344 | struct Foo { i: i32 } |
1324 | 1345 | ||
1325 | impl Foo { | 1346 | impl Foo { |
1326 | fn f(<|>self) -> i32 { | 1347 | fn f($0self) -> i32 { |
1327 | self.i | 1348 | self.i |
1328 | } | 1349 | } |
1329 | } | 1350 | } |
@@ -1350,7 +1371,7 @@ struct Foo { i: i32 } | |||
1350 | impl Foo { | 1371 | impl Foo { |
1351 | fn f(&self) -> i32 { | 1372 | fn f(&self) -> i32 { |
1352 | let self_var = 1; | 1373 | let self_var = 1; |
1353 | self<|>.i | 1374 | self$0.i |
1354 | } | 1375 | } |
1355 | } | 1376 | } |
1356 | "#, | 1377 | "#, |
@@ -1373,7 +1394,7 @@ impl Foo { | |||
1373 | check( | 1394 | check( |
1374 | "bar", | 1395 | "bar", |
1375 | r#" | 1396 | r#" |
1376 | struct Foo { i<|>: i32 } | 1397 | struct Foo { i$0: i32 } |
1377 | 1398 | ||
1378 | fn foo(bar: i32) -> Foo { | 1399 | fn foo(bar: i32) -> Foo { |
1379 | Foo { i: bar } | 1400 | Foo { i: bar } |
@@ -1394,7 +1415,7 @@ fn foo(bar: i32) -> Foo { | |||
1394 | check( | 1415 | check( |
1395 | "baz", | 1416 | "baz", |
1396 | r#" | 1417 | r#" |
1397 | struct Foo { i<|>: i32 } | 1418 | struct Foo { i$0: i32 } |
1398 | 1419 | ||
1399 | fn foo(foo: Foo) { | 1420 | fn foo(foo: Foo) { |
1400 | let Foo { i: baz } = foo; | 1421 | let Foo { i: baz } = foo; |
@@ -1433,7 +1454,7 @@ struct Foo { | |||
1433 | 1454 | ||
1434 | fn foo(foo: Foo) { | 1455 | fn foo(foo: Foo) { |
1435 | let Foo { i: b } = foo; | 1456 | let Foo { i: b } = foo; |
1436 | let _ = b<|>; | 1457 | let _ = b$0; |
1437 | } | 1458 | } |
1438 | "#, | 1459 | "#, |
1439 | expected_fixture, | 1460 | expected_fixture, |
@@ -1447,7 +1468,7 @@ struct Foo { | |||
1447 | 1468 | ||
1448 | fn foo(foo: Foo) { | 1469 | fn foo(foo: Foo) { |
1449 | let Foo { i } = foo; | 1470 | let Foo { i } = foo; |
1450 | let _ = i<|>; | 1471 | let _ = i$0; |
1451 | } | 1472 | } |
1452 | "#, | 1473 | "#, |
1453 | expected_fixture, | 1474 | expected_fixture, |
@@ -1464,7 +1485,7 @@ struct Foo { | |||
1464 | } | 1485 | } |
1465 | 1486 | ||
1466 | fn foo(Foo { i }: foo) -> i32 { | 1487 | fn foo(Foo { i }: foo) -> i32 { |
1467 | i<|> | 1488 | i$0 |
1468 | } | 1489 | } |
1469 | "#, | 1490 | "#, |
1470 | r#" | 1491 | r#" |
@@ -1481,6 +1502,7 @@ fn foo(Foo { i: bar }: foo) -> i32 { | |||
1481 | 1502 | ||
1482 | #[test] | 1503 | #[test] |
1483 | fn test_rename_lifetimes() { | 1504 | fn test_rename_lifetimes() { |
1505 | mark::check!(rename_lifetime); | ||
1484 | check( | 1506 | check( |
1485 | "'yeeee", | 1507 | "'yeeee", |
1486 | r#" | 1508 | r#" |
@@ -1488,7 +1510,7 @@ trait Foo<'a> { | |||
1488 | fn foo() -> &'a (); | 1510 | fn foo() -> &'a (); |
1489 | } | 1511 | } |
1490 | impl<'a> Foo<'a> for &'a () { | 1512 | impl<'a> Foo<'a> for &'a () { |
1491 | fn foo() -> &'a<|> () { | 1513 | fn foo() -> &'a$0 () { |
1492 | unimplemented!() | 1514 | unimplemented!() |
1493 | } | 1515 | } |
1494 | } | 1516 | } |
@@ -1520,7 +1542,7 @@ fn main() { | |||
1520 | let test_variable = CustomOption::Some(22); | 1542 | let test_variable = CustomOption::Some(22); |
1521 | 1543 | ||
1522 | match test_variable { | 1544 | match test_variable { |
1523 | CustomOption::Some(foo<|>) if foo == 11 => {} | 1545 | CustomOption::Some(foo$0) if foo == 11 => {} |
1524 | _ => (), | 1546 | _ => (), |
1525 | } | 1547 | } |
1526 | }"#, | 1548 | }"#, |
@@ -1549,7 +1571,7 @@ fn main() { | |||
1549 | fn foo<'a>() -> &'a () { | 1571 | fn foo<'a>() -> &'a () { |
1550 | 'a: { | 1572 | 'a: { |
1551 | 'b: loop { | 1573 | 'b: loop { |
1552 | break 'a<|>; | 1574 | break 'a$0; |
1553 | } | 1575 | } |
1554 | } | 1576 | } |
1555 | } | 1577 | } |
@@ -1565,4 +1587,24 @@ fn foo<'a>() -> &'a () { | |||
1565 | "#, | 1587 | "#, |
1566 | ) | 1588 | ) |
1567 | } | 1589 | } |
1590 | |||
1591 | #[test] | ||
1592 | fn test_self_to_self() { | ||
1593 | mark::check!(rename_self_to_self); | ||
1594 | check( | ||
1595 | "self", | ||
1596 | r#" | ||
1597 | struct Foo; | ||
1598 | impl Foo { | ||
1599 | fn foo(self$0) {} | ||
1600 | } | ||
1601 | "#, | ||
1602 | r#" | ||
1603 | struct Foo; | ||
1604 | impl Foo { | ||
1605 | fn foo(self) {} | ||
1606 | } | ||
1607 | "#, | ||
1608 | ) | ||
1609 | } | ||
1568 | } | 1610 | } |