aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-17 13:45:27 +0000
committerGitHub <[email protected]>2021-02-17 13:45:27 +0000
commit4054525c418085db4ceb2df70475a1ac9c019aff (patch)
tree64adbc8c62df3a6ebbe8c1a799589a94ddfbf490 /crates
parent056601b41fbc5208cae5d996ec7fd18526d79e41 (diff)
parente1dbf43cf85f84c3a7e40f9731fc1f7ac96f8979 (diff)
Merge #7699
7699: Implement ast::AstNode for NameLike and move it to node_ext r=matklad a=Veykril With this `search`(and 2 other modules) don't necessarily go through 3 calls of `find_node_at_offset_with_descend` to find the correct node. Also makes the code that searches for NameLikes a bit easier on the eyes imo, though that can be fixed with just a helper function as well so its not that relevant. Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_expand/src/name.rs13
-rw-r--r--crates/ide/src/references.rs38
-rw-r--r--crates/ide/src/references/rename.rs51
-rw-r--r--crates/ide_db/src/search.rs66
-rw-r--r--crates/syntax/src/ast.rs4
-rw-r--r--crates/syntax/src/ast/node_ext.rs61
6 files changed, 118 insertions, 115 deletions
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index c7609e90d..74cf64aab 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -87,11 +87,18 @@ impl AsName for ast::Name {
87 } 87 }
88} 88}
89 89
90impl AsName for ast::NameOrNameRef { 90impl AsName for ast::Lifetime {
91 fn as_name(&self) -> Name {
92 Name::resolve(self.text())
93 }
94}
95
96impl AsName for ast::NameLike {
91 fn as_name(&self) -> Name { 97 fn as_name(&self) -> Name {
92 match self { 98 match self {
93 ast::NameOrNameRef::Name(it) => it.as_name(), 99 ast::NameLike::Name(it) => it.as_name(),
94 ast::NameOrNameRef::NameRef(it) => it.as_name(), 100 ast::NameLike::NameRef(it) => it.as_name(),
101 ast::NameLike::Lifetime(it) => it.as_name(),
95 } 102 }
96 } 103 }
97} 104}
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index a83b82f1b..55f95ebae 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -101,29 +101,21 @@ fn find_def(
101 syntax: &SyntaxNode, 101 syntax: &SyntaxNode,
102 position: FilePosition, 102 position: FilePosition,
103) -> Option<Definition> { 103) -> Option<Definition> {
104 if let Some(name) = sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset) 104 let def = match sema.find_node_at_offset_with_descend(syntax, position.offset)? {
105 { 105 ast::NameLike::NameRef(name_ref) => {
106 let class = NameClass::classify(sema, &name)?; 106 NameRefClass::classify(sema, &name_ref)?.referenced(sema.db)
107 Some(class.referenced_or_defined(sema.db)) 107 }
108 } else if let Some(lifetime) = 108 ast::NameLike::Name(name) => {
109 sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) 109 NameClass::classify(sema, &name)?.referenced_or_defined(sema.db)
110 { 110 }
111 let def = if let Some(def) = 111 ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
112 NameRefClass::classify_lifetime(sema, &lifetime).map(|class| class.referenced(sema.db)) 112 .map(|class| class.referenced(sema.db))
113 { 113 .or_else(|| {
114 def 114 NameClass::classify_lifetime(sema, &lifetime)
115 } else { 115 .map(|class| class.referenced_or_defined(sema.db))
116 NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db) 116 })?,
117 }; 117 };
118 Some(def) 118 Some(def)
119 } else if let Some(name_ref) =
120 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)
121 {
122 let class = NameRefClass::classify(sema, &name_ref)?;
123 Some(class.referenced(sema.db))
124 } else {
125 None
126 }
127} 119}
128 120
129fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { 121fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> {
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index a4b320227..175ddd759 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -6,7 +6,7 @@ use hir::{HasSource, InFile, Module, ModuleDef, ModuleSource, Semantics};
6use ide_db::{ 6use ide_db::{
7 base_db::{AnchoredPathBuf, FileId}, 7 base_db::{AnchoredPathBuf, FileId},
8 defs::{Definition, NameClass, NameRefClass}, 8 defs::{Definition, NameClass, NameRefClass},
9 search::{FileReference, NameLike}, 9 search::FileReference,
10 RootDatabase, 10 RootDatabase,
11}; 11};
12use stdx::never; 12use stdx::never;
@@ -47,12 +47,13 @@ pub(crate) fn prepare_rename(
47 let sema = Semantics::new(db); 47 let sema = Semantics::new(db);
48 let source_file = sema.parse(position.file_id); 48 let source_file = sema.parse(position.file_id);
49 let syntax = source_file.syntax(); 49 let syntax = source_file.syntax();
50 let range = match &find_name_like(&sema, &syntax, position) 50 let range = match &sema
51 .find_node_at_offset_with_descend(&syntax, position.offset)
51 .ok_or_else(|| format_err!("No references found at position"))? 52 .ok_or_else(|| format_err!("No references found at position"))?
52 { 53 {
53 NameLike::Name(it) => it.syntax(), 54 ast::NameLike::Name(it) => it.syntax(),
54 NameLike::NameRef(it) => it.syntax(), 55 ast::NameLike::NameRef(it) => it.syntax(),
55 NameLike::Lifetime(it) => it.syntax(), 56 ast::NameLike::Lifetime(it) => it.syntax(),
56 } 57 }
57 .text_range(); 58 .text_range();
58 Ok(RangeInfo::new(range, ())) 59 Ok(RangeInfo::new(range, ()))
@@ -121,50 +122,28 @@ fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> {
121 } 122 }
122} 123}
123 124
124fn find_name_like(
125 sema: &Semantics<RootDatabase>,
126 syntax: &SyntaxNode,
127 position: FilePosition,
128) -> Option<NameLike> {
129 let namelike = if let Some(name_ref) =
130 sema.find_node_at_offset_with_descend::<ast::NameRef>(syntax, position.offset)
131 {
132 NameLike::NameRef(name_ref)
133 } else if let Some(name) =
134 sema.find_node_at_offset_with_descend::<ast::Name>(syntax, position.offset)
135 {
136 NameLike::Name(name)
137 } else if let Some(lifetime) =
138 sema.find_node_at_offset_with_descend::<ast::Lifetime>(syntax, position.offset)
139 {
140 NameLike::Lifetime(lifetime)
141 } else {
142 return None;
143 };
144 Some(namelike)
145}
146
147fn find_definition( 125fn find_definition(
148 sema: &Semantics<RootDatabase>, 126 sema: &Semantics<RootDatabase>,
149 syntax: &SyntaxNode, 127 syntax: &SyntaxNode,
150 position: FilePosition, 128 position: FilePosition,
151) -> RenameResult<Definition> { 129) -> RenameResult<Definition> {
152 match find_name_like(sema, syntax, position) 130 match sema
131 .find_node_at_offset_with_descend(syntax, position.offset)
153 .ok_or_else(|| format_err!("No references found at position"))? 132 .ok_or_else(|| format_err!("No references found at position"))?
154 { 133 {
155 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet 134 // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
156 NameLike::Name(name) 135 ast::NameLike::Name(name)
157 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => 136 if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
158 { 137 {
159 bail!("Renaming aliases is currently unsupported") 138 bail!("Renaming aliases is currently unsupported")
160 } 139 }
161 NameLike::Name(name) => { 140 ast::NameLike::Name(name) => {
162 NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db)) 141 NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db))
163 } 142 }
164 NameLike::NameRef(name_ref) => { 143 ast::NameLike::NameRef(name_ref) => {
165 NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db)) 144 NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db))
166 } 145 }
167 NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) 146 ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
168 .map(|class| NameRefClass::referenced(class, sema.db)) 147 .map(|class| NameRefClass::referenced(class, sema.db))
169 .or_else(|| { 148 .or_else(|| {
170 NameClass::classify_lifetime(sema, &lifetime) 149 NameClass::classify_lifetime(sema, &lifetime)
@@ -187,10 +166,12 @@ fn source_edit_from_references(
187 // if the ranges differ then the node is inside a macro call, we can't really attempt 166 // if the ranges differ then the node is inside a macro call, we can't really attempt
188 // to make special rewrites like shorthand syntax and such, so just rename the node in 167 // to make special rewrites like shorthand syntax and such, so just rename the node in
189 // the macro input 168 // the macro input
190 NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == reference.range => { 169 ast::NameLike::NameRef(name_ref)
170 if name_ref.syntax().text_range() == reference.range =>
171 {
191 source_edit_from_name_ref(name_ref, new_name, def) 172 source_edit_from_name_ref(name_ref, new_name, def)
192 } 173 }
193 NameLike::Name(name) if name.syntax().text_range() == reference.range => { 174 ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => {
194 source_edit_from_name(name, new_name) 175 source_edit_from_name(name, new_name)
195 } 176 }
196 _ => None, 177 _ => None,
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 22dd172f7..ba8bea002 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -53,33 +53,9 @@ impl IntoIterator for UsageSearchResult {
53} 53}
54 54
55#[derive(Debug, Clone)] 55#[derive(Debug, Clone)]
56pub enum NameLike {
57 NameRef(ast::NameRef),
58 Name(ast::Name),
59 Lifetime(ast::Lifetime),
60}
61
62impl NameLike {
63 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
64 match self {
65 NameLike::NameRef(name_ref) => Some(name_ref),
66 _ => None,
67 }
68 }
69}
70
71mod __ {
72 use super::{
73 ast::{Lifetime, Name, NameRef},
74 NameLike,
75 };
76 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
77}
78
79#[derive(Debug, Clone)]
80pub struct FileReference { 56pub struct FileReference {
81 pub range: TextRange, 57 pub range: TextRange,
82 pub name: NameLike, 58 pub name: ast::NameLike,
83 pub access: Option<ReferenceAccess>, 59 pub access: Option<ReferenceAccess>,
84} 60}
85 61
@@ -300,6 +276,7 @@ impl<'a> FindUsages<'a> {
300 pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> { 276 pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
301 self.set_scope(Some(scope)) 277 self.set_scope(Some(scope))
302 } 278 }
279
303 pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> { 280 pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
304 assert!(self.scope.is_none()); 281 assert!(self.scope.is_none());
305 self.scope = scope; 282 self.scope = scope;
@@ -355,18 +332,23 @@ impl<'a> FindUsages<'a> {
355 continue; 332 continue;
356 } 333 }
357 334
358 if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) { 335 if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) {
359 if self.found_name_ref(&name_ref, sink) { 336 match name {
360 return; 337 ast::NameLike::NameRef(name_ref) => {
361 } 338 if self.found_name_ref(&name_ref, sink) {
362 } else if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { 339 return;
363 if self.found_name(&name, sink) { 340 }
364 return; 341 }
365 } 342 ast::NameLike::Name(name) => {
366 } else if let Some(lifetime) = sema.find_node_at_offset_with_descend(&tree, offset) 343 if self.found_name(&name, sink) {
367 { 344 return;
368 if self.found_lifetime(&lifetime, sink) { 345 }
369 return; 346 }
347 ast::NameLike::Lifetime(lifetime) => {
348 if self.found_lifetime(&lifetime, sink) {
349 return;
350 }
351 }
370 } 352 }
371 } 353 }
372 } 354 }
@@ -383,7 +365,7 @@ impl<'a> FindUsages<'a> {
383 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); 365 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
384 let reference = FileReference { 366 let reference = FileReference {
385 range, 367 range,
386 name: NameLike::Lifetime(lifetime.clone()), 368 name: ast::NameLike::Lifetime(lifetime.clone()),
387 access: None, 369 access: None,
388 }; 370 };
389 sink(file_id, reference) 371 sink(file_id, reference)
@@ -402,7 +384,7 @@ impl<'a> FindUsages<'a> {
402 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); 384 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
403 let reference = FileReference { 385 let reference = FileReference {
404 range, 386 range,
405 name: NameLike::NameRef(name_ref.clone()), 387 name: ast::NameLike::NameRef(name_ref.clone()),
406 access: reference_access(&def, &name_ref), 388 access: reference_access(&def, &name_ref),
407 }; 389 };
408 sink(file_id, reference) 390 sink(file_id, reference)
@@ -412,12 +394,12 @@ impl<'a> FindUsages<'a> {
412 let reference = match self.def { 394 let reference = match self.def {
413 Definition::Field(_) if &field == self.def => FileReference { 395 Definition::Field(_) if &field == self.def => FileReference {
414 range, 396 range,
415 name: NameLike::NameRef(name_ref.clone()), 397 name: ast::NameLike::NameRef(name_ref.clone()),
416 access: reference_access(&field, &name_ref), 398 access: reference_access(&field, &name_ref),
417 }, 399 },
418 Definition::Local(l) if &local == l => FileReference { 400 Definition::Local(l) if &local == l => FileReference {
419 range, 401 range,
420 name: NameLike::NameRef(name_ref.clone()), 402 name: ast::NameLike::NameRef(name_ref.clone()),
421 access: reference_access(&Definition::Local(local), &name_ref), 403 access: reference_access(&Definition::Local(local), &name_ref),
422 }, 404 },
423 _ => return false, // not a usage 405 _ => return false, // not a usage
@@ -441,7 +423,7 @@ impl<'a> FindUsages<'a> {
441 let FileRange { file_id, range } = self.sema.original_range(name.syntax()); 423 let FileRange { file_id, range } = self.sema.original_range(name.syntax());
442 let reference = FileReference { 424 let reference = FileReference {
443 range, 425 range,
444 name: NameLike::Name(name.clone()), 426 name: ast::NameLike::Name(name.clone()),
445 // FIXME: mutable patterns should have `Write` access 427 // FIXME: mutable patterns should have `Write` access
446 access: Some(ReferenceAccess::Read), 428 access: Some(ReferenceAccess::Read),
447 }; 429 };
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index a25ff655e..72214a4f0 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -19,8 +19,8 @@ pub use self::{
19 expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp}, 19 expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
20 generated::{nodes::*, tokens::*}, 20 generated::{nodes::*, tokens::*},
21 node_ext::{ 21 node_ext::{
22 AttrKind, FieldKind, Macro, NameOrNameRef, PathSegmentKind, SelfParamKind, 22 AttrKind, FieldKind, Macro, NameLike, PathSegmentKind, SelfParamKind, SlicePatComponents,
23 SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, 23 StructKind, TypeBoundKind, VisibilityKind,
24 }, 24 },
25 token_ext::*, 25 token_ext::*,
26 traits::*, 26 traits::*,
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 307e150e9..c1f8101b2 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -298,25 +298,66 @@ impl ast::RecordExprField {
298} 298}
299 299
300#[derive(Debug, Clone, PartialEq)] 300#[derive(Debug, Clone, PartialEq)]
301pub enum NameOrNameRef { 301pub enum NameLike {
302 Name(ast::Name),
303 NameRef(ast::NameRef), 302 NameRef(ast::NameRef),
303 Name(ast::Name),
304 Lifetime(ast::Lifetime),
304} 305}
305 306
306impl fmt::Display for NameOrNameRef { 307impl NameLike {
308 pub fn as_name_ref(&self) -> Option<&ast::NameRef> {
309 match self {
310 NameLike::NameRef(name_ref) => Some(name_ref),
311 _ => None,
312 }
313 }
314}
315
316impl ast::AstNode for NameLike {
317 fn can_cast(kind: SyntaxKind) -> bool {
318 matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME)
319 }
320 fn cast(syntax: SyntaxNode) -> Option<Self> {
321 let res = match syntax.kind() {
322 SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }),
323 SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }),
324 SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }),
325 _ => return None,
326 };
327 Some(res)
328 }
329 fn syntax(&self) -> &SyntaxNode {
330 match self {
331 NameLike::NameRef(it) => it.syntax(),
332 NameLike::Name(it) => it.syntax(),
333 NameLike::Lifetime(it) => it.syntax(),
334 }
335 }
336}
337
338impl fmt::Display for NameLike {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 match self { 340 match self {
309 NameOrNameRef::Name(it) => fmt::Display::fmt(it, f), 341 NameLike::Name(it) => fmt::Display::fmt(it, f),
310 NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f), 342 NameLike::NameRef(it) => fmt::Display::fmt(it, f),
343 NameLike::Lifetime(it) => fmt::Display::fmt(it, f),
311 } 344 }
312 } 345 }
313} 346}
314 347
348mod __ {
349 use super::{
350 ast::{Lifetime, Name, NameRef},
351 NameLike,
352 };
353 stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
354}
355
315impl ast::RecordPatField { 356impl ast::RecordPatField {
316 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> { 357 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
317 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?; 358 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
318 match candidate.field_name()? { 359 match candidate.field_name()? {
319 NameOrNameRef::NameRef(name_ref) if name_ref == *field_name => Some(candidate), 360 NameLike::NameRef(name_ref) if name_ref == *field_name => Some(candidate),
320 _ => None, 361 _ => None,
321 } 362 }
322 } 363 }
@@ -325,19 +366,19 @@ impl ast::RecordPatField {
325 let candidate = 366 let candidate =
326 field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?; 367 field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
327 match candidate.field_name()? { 368 match candidate.field_name()? {
328 NameOrNameRef::Name(name) if name == *field_name => Some(candidate), 369 NameLike::Name(name) if name == *field_name => Some(candidate),
329 _ => None, 370 _ => None,
330 } 371 }
331 } 372 }
332 373
333 /// Deals with field init shorthand 374 /// Deals with field init shorthand
334 pub fn field_name(&self) -> Option<NameOrNameRef> { 375 pub fn field_name(&self) -> Option<NameLike> {
335 if let Some(name_ref) = self.name_ref() { 376 if let Some(name_ref) = self.name_ref() {
336 return Some(NameOrNameRef::NameRef(name_ref)); 377 return Some(NameLike::NameRef(name_ref));
337 } 378 }
338 if let Some(ast::Pat::IdentPat(pat)) = self.pat() { 379 if let Some(ast::Pat::IdentPat(pat)) = self.pat() {
339 let name = pat.name()?; 380 let name = pat.name()?;
340 return Some(NameOrNameRef::Name(name)); 381 return Some(NameLike::Name(name));
341 } 382 }
342 None 383 None
343 } 384 }