aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/display/navigation_target.rs14
-rw-r--r--crates/ide/src/goto_definition.rs5
-rw-r--r--crates/ide/src/hover.rs5
-rw-r--r--crates/ide/src/references/rename.rs76
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs22
5 files changed, 49 insertions, 73 deletions
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 685052e7f..00e601244 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -400,15 +400,13 @@ impl TryToNav for hir::GenericParam {
400impl ToNav for hir::Local { 400impl ToNav for hir::Local {
401 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 401 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
402 let src = self.source(db); 402 let src = self.source(db);
403 let (node, focus_range) = match &src.value { 403 let (node, name) = match &src.value {
404 Either::Left(bind_pat) => ( 404 Either::Left(bind_pat) => (bind_pat.syntax().clone(), bind_pat.name()),
405 bind_pat.syntax().clone(), 405 Either::Right(it) => (it.syntax().clone(), it.name()),
406 bind_pat
407 .name()
408 .map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range),
409 ),
410 Either::Right(it) => (it.syntax().clone(), it.self_token().map(|it| it.text_range())),
411 }; 406 };
407 let focus_range =
408 name.map(|it| src.with_value(&it.syntax().clone()).original_file_range(db).range);
409
412 let full_range = src.with_value(&node).original_file_range(db); 410 let full_range = src.with_value(&node).original_file_range(db);
413 let name = match self.name(db) { 411 let name = match self.name(db) {
414 Some(it) => it.to_string().into(), 412 Some(it) => it.to_string().into(),
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 988a5668f..a1d2bce1d 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -55,11 +55,6 @@ pub(crate) fn goto_definition(
55 } else { 55 } else {
56 reference_definition(&sema, Either::Left(&lt)).to_vec() 56 reference_definition(&sema, Either::Left(&lt)).to_vec()
57 }, 57 },
58 ast::SelfParam(self_param) => {
59 let def = NameClass::classify_self_param(&sema, &self_param)?.referenced_or_defined(sema.db);
60 let nav = def.try_to_nav(sema.db)?;
61 vec![nav]
62 },
63 _ => return None, 58 _ => return None,
64 } 59 }
65 }; 60 };
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 6022bd275..2024acd94 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -98,7 +98,6 @@ pub(crate) fn hover(
98 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), 98 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
99 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) 99 ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime)
100 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), 100 .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)),
101 ast::SelfParam(self_param) => NameClass::classify_self_param(&sema, &self_param).and_then(|d| d.defined(sema.db)),
102 _ => None, 101 _ => None,
103 } 102 }
104 }; 103 };
@@ -3223,7 +3222,7 @@ impl Foo {
3223} 3222}
3224"#, 3223"#,
3225 expect![[r#" 3224 expect![[r#"
3226 *&self* 3225 *self*
3227 3226
3228 ```rust 3227 ```rust
3229 &Foo 3228 &Foo
@@ -3243,7 +3242,7 @@ impl Foo {
3243} 3242}
3244"#, 3243"#,
3245 expect![[r#" 3244 expect![[r#"
3246 *self: Arc<Foo>* 3245 *self*
3247 3246
3248 ```rust 3247 ```rust
3249 Arc<Foo> 3248 Arc<Foo>
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 9ac4af026..4df189c98 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,12 +1,9 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::{ 2use std::fmt::{self, Display};
3 convert::TryInto,
4 fmt::{self, Display},
5};
6 3
7use hir::{Module, ModuleDef, ModuleSource, Semantics}; 4use hir::{Module, ModuleDef, ModuleSource, Semantics};
8use ide_db::{ 5use ide_db::{
9 base_db::{AnchoredPathBuf, FileId, FileRange, SourceDatabaseExt}, 6 base_db::{AnchoredPathBuf, FileId, FileRange},
10 defs::{Definition, NameClass, NameRefClass}, 7 defs::{Definition, NameClass, NameRefClass},
11 search::FileReference, 8 search::FileReference,
12 RootDatabase, 9 RootDatabase,
@@ -14,14 +11,14 @@ use ide_db::{
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, T, 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 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, 20 FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange,
24 TextRange, TextSize, 21 TextRange,
25}; 22};
26 23
27type RenameResult<T> = Result<T, RenameError>; 24type RenameResult<T> = Result<T, RenameError>;
@@ -52,10 +49,6 @@ pub(crate) fn prepare_rename(
52 let syntax = source_file.syntax(); 49 let syntax = source_file.syntax();
53 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 50 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
54 rename_mod(&sema, position, module, "dummy") 51 rename_mod(&sema, position, module, "dummy")
55 } else if let Some(self_token) =
56 syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])
57 {
58 rename_self_to_param(&sema, position, self_token, "dummy")
59 } else { 52 } else {
60 let RangeInfo { range, .. } = find_all_refs(&sema, position)?; 53 let RangeInfo { range, .. } = find_all_refs(&sema, position)?;
61 Ok(RangeInfo::new(range, SourceChange::default())) 54 Ok(RangeInfo::new(range, SourceChange::default()))
@@ -82,10 +75,6 @@ pub(crate) fn rename_with_semantics(
82 75
83 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 76 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
84 rename_mod(&sema, position, module, new_name) 77 rename_mod(&sema, position, module, new_name)
85 } else if let Some(self_token) =
86 syntax.token_at_offset(position.offset).find(|t| t.kind() == T![self])
87 {
88 rename_self_to_param(&sema, position, self_token, new_name)
89 } else { 78 } else {
90 rename_reference(&sema, position, new_name) 79 rename_reference(&sema, position, new_name)
91 } 80 }
@@ -108,7 +97,7 @@ pub(crate) fn will_rename_file(
108 Some(change) 97 Some(change)
109} 98}
110 99
111#[derive(Debug, PartialEq)] 100#[derive(Copy, Clone, Debug, PartialEq)]
112enum IdentifierKind { 101enum IdentifierKind {
113 Ident, 102 Ident,
114 Lifetime, 103 Lifetime,
@@ -375,53 +364,50 @@ fn text_edit_from_self_param(
375fn rename_self_to_param( 364fn rename_self_to_param(
376 sema: &Semantics<RootDatabase>, 365 sema: &Semantics<RootDatabase>,
377 position: FilePosition, 366 position: FilePosition,
378 self_token: SyntaxToken,
379 new_name: &str, 367 new_name: &str,
368 ident_kind: IdentifierKind,
369 range: TextRange,
370 refs: ReferenceSearchResult,
380) -> Result<RangeInfo<SourceChange>, RenameError> { 371) -> Result<RangeInfo<SourceChange>, RenameError> {
381 let ident_kind = check_identifier(new_name)?;
382 match ident_kind { 372 match ident_kind {
383 IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name), 373 IdentifierKind::Lifetime => bail!("Invalid name `{}`: not an identifier", new_name),
384 IdentifierKind::ToSelf => { 374 IdentifierKind::ToSelf => {
385 // no-op 375 // no-op
386 mark::hit!(rename_self_to_self); 376 mark::hit!(rename_self_to_self);
387 return Ok(RangeInfo::new(self_token.text_range(), SourceChange::default())); 377 return Ok(RangeInfo::new(range, SourceChange::default()));
388 } 378 }
389 _ => (), 379 _ => (),
390 } 380 }
391 let source_file = sema.parse(position.file_id); 381 let source_file = sema.parse(position.file_id);
392 let syn = source_file.syntax(); 382 let syn = source_file.syntax();
393 383
394 let text = sema.db.file_text(position.file_id);
395 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)
396 .ok_or_else(|| format_err!("No surrounding method declaration found"))?; 385 .ok_or_else(|| format_err!("No surrounding method declaration found"))?;
397 let search_range = fn_def.syntax().text_range();
398 386
399 let mut source_change = SourceChange::default(); 387 let mut source_change = SourceChange::default();
400 388 if let Some(self_param) = fn_def.param_list().and_then(|it| it.self_param()) {
401 for (idx, _) in text.match_indices("self") { 389 if self_param
402 let offset: TextSize = idx.try_into().unwrap(); 390 .syntax()
403 if !search_range.contains_inclusive(offset) { 391 .text_range()
404 continue; 392 .contains_range(refs.declaration().nav.focus_or_full_range())
405 } 393 {
406 if let Some(ref usage) = syn.token_at_offset(offset).find(|t| t.kind() == T![self]) { 394 let edit = text_edit_from_self_param(syn, &self_param, new_name)
407 let edit = if let Some(ref self_param) = ast::SelfParam::cast(usage.parent()) { 395 .ok_or_else(|| format_err!("No target type found"))?;
408 text_edit_from_self_param(syn, self_param, new_name)
409 .ok_or_else(|| format_err!("No target type found"))?
410 } else {
411 TextEdit::replace(usage.text_range(), String::from(new_name))
412 };
413 source_change.insert_source_edit(position.file_id, edit); 396 source_change.insert_source_edit(position.file_id, edit);
414 }
415 }
416 397
417 if source_change.source_file_edits.len() > 1 && ident_kind == IdentifierKind::Underscore { 398 source_change.extend(refs.references().iter().map(|(&file_id, references)| {
418 bail!("Cannot rename reference to `_` as it is being referenced multiple times"); 399 source_edit_from_references(sema, file_id, &references, new_name)
419 } 400 }));
420 401
421 let range = ast::SelfParam::cast(self_token.parent()) 402 if source_change.source_file_edits.len() > 1 && ident_kind == IdentifierKind::Underscore
422 .map_or(self_token.text_range(), |p| p.syntax().text_range()); 403 {
404 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
405 }
423 406
424 Ok(RangeInfo::new(range, source_change)) 407 return Ok(RangeInfo::new(range, source_change));
408 }
409 }
410 Err(format_err!("Method has no self param"))
425} 411}
426 412
427fn rename_reference( 413fn rename_reference(
@@ -444,8 +430,9 @@ fn rename_reference(
444 mark::hit!(rename_not_an_ident_ref); 430 mark::hit!(rename_not_an_ident_ref);
445 bail!("Invalid name `{}`: not an identifier", new_name) 431 bail!("Invalid name `{}`: not an identifier", new_name)
446 } 432 }
447 (IdentifierKind::ToSelf, ReferenceKind::SelfParam) => { 433 (_, ReferenceKind::SelfParam) => {
448 unreachable!("rename_self_to_param should've been called instead") 434 mark::hit!(rename_self_to_param);
435 return rename_self_to_param(sema, position, new_name, ident_kind, range, refs);
449 } 436 }
450 (IdentifierKind::ToSelf, _) => { 437 (IdentifierKind::ToSelf, _) => {
451 mark::hit!(rename_to_self); 438 mark::hit!(rename_to_self);
@@ -1350,6 +1337,7 @@ impl Foo {
1350 1337
1351 #[test] 1338 #[test]
1352 fn test_owned_self_to_parameter() { 1339 fn test_owned_self_to_parameter() {
1340 mark::check!(rename_self_to_param);
1353 check( 1341 check(
1354 "foo", 1342 "foo",
1355 r#" 1343 r#"
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 87578e70a..8625ef5df 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -68,7 +68,8 @@ pub(super) fn element(
68 NAME_REF => { 68 NAME_REF => {
69 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); 69 let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
70 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| { 70 highlight_func_by_name_ref(sema, &name_ref).unwrap_or_else(|| {
71 match NameRefClass::classify(sema, &name_ref) { 71 let is_self = name_ref.self_token().is_some();
72 let h = match NameRefClass::classify(sema, &name_ref) {
72 Some(name_kind) => match name_kind { 73 Some(name_kind) => match name_kind {
73 NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(), 74 NameRefClass::ExternCrate(_) => HlTag::Symbol(SymbolKind::Module).into(),
74 NameRefClass::Definition(def) => { 75 NameRefClass::Definition(def) => {
@@ -108,6 +109,11 @@ pub(super) fn element(
108 highlight_name_ref_by_syntax(name_ref, sema) 109 highlight_name_ref_by_syntax(name_ref, sema)
109 } 110 }
110 None => HlTag::UnresolvedReference.into(), 111 None => HlTag::UnresolvedReference.into(),
112 };
113 if h.tag == HlTag::Symbol(SymbolKind::Module) && is_self {
114 HlTag::Symbol(SymbolKind::SelfParam).into()
115 } else {
116 h
111 } 117 }
112 }) 118 })
113 } 119 }
@@ -225,18 +231,8 @@ pub(super) fn element(
225 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow, 231 T![for] if !is_child_of_impl(&element) => h | HlMod::ControlFlow,
226 T![unsafe] => h | HlMod::Unsafe, 232 T![unsafe] => h | HlMod::Unsafe,
227 T![true] | T![false] => HlTag::BoolLiteral.into(), 233 T![true] | T![false] => HlTag::BoolLiteral.into(),
228 T![self] => { 234 // self is handled as either a Name or NameRef already
229 let self_param = element.parent().and_then(ast::SelfParam::cast); 235 T![self] => return None,
230 if let Some(NameClass::Definition(def)) = self_param
231 .and_then(|self_param| NameClass::classify_self_param(sema, &self_param))
232 {
233 highlight_def(db, def) | HlMod::Definition
234 } else if element.ancestors().any(|it| it.kind() == USE_TREE) {
235 HlTag::Symbol(SymbolKind::SelfParam).into()
236 } else {
237 return None;
238 }
239 }
240 T![ref] => element 236 T![ref] => element
241 .parent() 237 .parent()
242 .and_then(ast::IdentPat::cast) 238 .and_then(ast::IdentPat::cast)