aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/references
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/references')
-rw-r--r--crates/ide/src/references/rename.rs688
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
2use std::{ 2use std::fmt::{self, Display};
3 convert::TryInto,
4 error::Error,
5 fmt::{self, Display},
6};
7 3
8use hir::{Module, ModuleDef, ModuleSource, Semantics}; 4use hir::{Module, ModuleDef, ModuleSource, Semantics};
9use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt};
10use ide_db::{ 5use 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};
14use syntax::{ 11use 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};
19use test_utils::mark; 16use test_utils::mark;
20use text_edit::TextEdit; 17use text_edit::TextEdit;
21 18
22use crate::{ 19use 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
24type RenameResult<T> = Result<T, RenameError>;
27#[derive(Debug)] 25#[derive(Debug)]
28pub struct RenameError(pub(crate) String); 26pub struct RenameError(pub(crate) String);
29 27
@@ -33,27 +31,27 @@ impl fmt::Display for RenameError {
33 } 31 }
34} 32}
35 33
36impl Error for RenameError {} 34macro_rules! format_err {
35 ($fmt:expr) => {RenameError(format!($fmt))};
36 ($fmt:expr, $($arg:tt)+) => {RenameError(format!($fmt, $($arg)+))}
37}
38
39macro_rules! bail {
40 ($($tokens:tt)*) => {return Err(format_err!($($tokens)*))}
41}
37 42
38pub(crate) fn prepare_rename( 43pub(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)]
101enum IdentifierKind {
102 Ident,
103 Lifetime,
104 ToSelf,
105 Underscore,
106}
107
108fn 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
130fn find_module_at_offset( 127fn 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
158fn source_edit_from_reference( 155fn 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
163fn 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
193fn edit_text_range_for_record_field_expr_or_pat( 204fn 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
268fn rename_to_self( 279fn 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
337fn text_edit_from_self_param( 337fn text_edit_from_self_param(
@@ -364,77 +364,93 @@ fn text_edit_from_self_param(
364fn rename_self_to_param( 364fn 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
404fn rename_reference( 413fn 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#"
554fn main() { 594fn 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#"
592macro_rules! foo {($i:ident) => {$i} } 632macro_rules! foo {($i:ident) => {$i} }
593fn main() { 633fn 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() {
613macro_rules! foo {($i:ident) => {$i} } 653macro_rules! foo {($i:ident) => {$i} }
614fn main() { 654fn 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() {
634macro_rules! define_fn {($id:ident) => { fn $id{} }} 674macro_rules! define_fn {($id:ident) => { fn $id{} }}
635define_fn!(foo); 675define_fn!(foo);
636fn main() { 676fn 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#"
655macro_rules! define_fn {($id:ident) => { fn $id{} }} 695macro_rules! define_fn {($id:ident) => { fn $id{} }}
656define_fn!(fo<|>o); 696define_fn!(fo$0o);
657fn main() { 697fn 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#"
691struct Foo { i<|>: i32 } 731struct Foo { i$0: i32 }
692 732
693impl Foo { 733impl 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#"
717struct Foo { i<|>: i32 } 757struct Foo { i$0: i32 }
718 758
719impl Foo { 759impl Foo {
720 fn new(i: i32) -> Self { 760 fn new(i: i32) -> Self {
@@ -743,7 +783,7 @@ impl Foo {
743struct Foo { i: i32 } 783struct Foo { i: i32 }
744 784
745impl Foo { 785impl 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#"
768struct Foo { i<|>: i32 } 808struct Foo { i$0: i32 }
769struct Bar { i: i32 } 809struct Bar { i: i32 }
770 810
771impl Bar { 811impl Bar {
@@ -794,7 +834,7 @@ impl Bar {
794 r#" 834 r#"
795struct Foo { i: i32 } 835struct Foo { i: i32 }
796 836
797fn baz(i<|>: i32) -> Self { 837fn 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 {
825mod bar; 865mod bar;
826 866
827//- /bar.rs 867//- /bar.rs
828mod foo<|>; 868mod 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() {}
883pub struct FooContent; 920pub struct FooContent;
884 921
885//- /bar.rs 922//- /bar.rs
886use crate::foo<|>::FooContent; 923use 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
946mod fo<|>o; 977mod 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
995mod outer { mod fo<|>o; } 1023mod 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#"
1044mod <|>foo { pub fn bar() {} } 1069mod $0foo { pub fn bar() {} }
1045 1070
1046fn main() { foo::bar(); } 1071fn main() { foo::bar(); }
1047"#, 1072"#,
@@ -1065,7 +1090,7 @@ fn f() {
1065} 1090}
1066 1091
1067//- /bar.rs 1092//- /bar.rs
1068pub mod foo<|>; 1093pub 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#"
1130mod foo { 1149mod foo {
1131 pub enum Foo { Bar<|> } 1150 pub enum Foo { Bar$0 }
1132} 1151}
1133 1152
1134fn func(f: foo::Foo) { 1153fn func(f: foo::Foo) {
@@ -1157,7 +1176,7 @@ fn func(f: foo::Foo) {
1157 "baz", 1176 "baz",
1158 r#" 1177 r#"
1159mod foo { 1178mod foo {
1160 pub struct Foo { pub bar<|>: uint } 1179 pub struct Foo { pub bar$0: uint }
1161} 1180}
1162 1181
1163fn foo(f: foo::Foo) { 1182fn 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#"
1184struct Foo { i: i32 } 1204struct Foo { i: i32 }
1185 1205
1186impl Foo { 1206impl 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 {
1205struct Foo { i: i32 } 1225struct Foo { i: i32 }
1206 1226
1207impl Foo { 1227impl 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#"
1230struct Foo { i: i32 } 1250struct Foo { i: i32 }
1231 1251
1232fn f(foo<|>: &mut Foo) -> i32 { 1252fn f(foo$0: &mut Foo) -> i32 {
1233 foo.i 1253 foo.i
1234} 1254}
1235"#, 1255"#,
@@ -1242,7 +1262,7 @@ struct Foo { i: i32 }
1242struct Bar; 1262struct Bar;
1243 1263
1244impl Bar { 1264impl 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#"
1259struct Foo { i: i32 } 1279struct Foo { i: i32 }
1260impl Foo { 1280impl 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#"
1275struct Foo { i: i32 } 1295struct Foo { i: i32 }
1276impl &Foo { 1296impl &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 {
1298struct Foo { i: i32 } 1318struct Foo { i: i32 }
1299 1319
1300impl Foo { 1320impl 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#"
1323struct Foo { i: i32 } 1344struct Foo { i: i32 }
1324 1345
1325impl Foo { 1346impl 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 }
1350impl Foo { 1371impl 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#"
1376struct Foo { i<|>: i32 } 1397struct Foo { i$0: i32 }
1377 1398
1378fn foo(bar: i32) -> Foo { 1399fn 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#"
1397struct Foo { i<|>: i32 } 1418struct Foo { i$0: i32 }
1398 1419
1399fn foo(foo: Foo) { 1420fn foo(foo: Foo) {
1400 let Foo { i: baz } = foo; 1421 let Foo { i: baz } = foo;
@@ -1433,7 +1454,7 @@ struct Foo {
1433 1454
1434fn foo(foo: Foo) { 1455fn 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
1448fn foo(foo: Foo) { 1469fn 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
1466fn foo(Foo { i }: foo) -> i32 { 1487fn 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}
1490impl<'a> Foo<'a> for &'a () { 1512impl<'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() {
1549fn foo<'a>() -> &'a () { 1571fn 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#"
1597struct Foo;
1598impl Foo {
1599 fn foo(self$0) {}
1600}
1601"#,
1602 r#"
1603struct Foo;
1604impl Foo {
1605 fn foo(self) {}
1606}
1607"#,
1608 )
1609 }
1568} 1610}