diff options
author | Lukas Wirth <[email protected]> | 2021-02-16 18:27:08 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-02-16 18:27:08 +0000 |
commit | e52bdc55ef05bae8e647a5a0a9f8c3605c4cdd34 (patch) | |
tree | 9204791d0e03e6407072d806737aa0ffd3a6d332 | |
parent | 80f9618f3775d22fddbfa6fac041aed6519eca4e (diff) |
Implement ast::AstNode for NameLike and move it to node_ext
-rw-r--r-- | crates/ide/src/references.rs | 38 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 51 | ||||
-rw-r--r-- | crates/ide_db/src/search.rs | 66 | ||||
-rw-r--r-- | crates/syntax/src/ast.rs | 2 | ||||
-rw-r--r-- | crates/syntax/src/ast/node_ext.rs | 46 |
5 files changed, 102 insertions, 101 deletions
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 | ||
129 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { | 121 | fn 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}; | |||
6 | use ide_db::{ | 6 | use 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 | }; |
12 | use stdx::never; | 12 | use 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 | ||
124 | fn 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 | |||
147 | fn find_definition( | 125 | fn 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)] |
56 | pub enum NameLike { | ||
57 | NameRef(ast::NameRef), | ||
58 | Name(ast::Name), | ||
59 | Lifetime(ast::Lifetime), | ||
60 | } | ||
61 | |||
62 | impl 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 | |||
71 | mod __ { | ||
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)] | ||
80 | pub struct FileReference { | 56 | pub 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..b3a24d39d 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs | |||
@@ -19,7 +19,7 @@ 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, NameOrNameRef, PathSegmentKind, SelfParamKind, |
23 | SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, | 23 | SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, |
24 | }, | 24 | }, |
25 | token_ext::*, | 25 | token_ext::*, |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 307e150e9..2fa7b8c1e 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -297,6 +297,52 @@ impl ast::RecordExprField { | |||
297 | } | 297 | } |
298 | } | 298 | } |
299 | 299 | ||
300 | #[derive(Debug, Clone)] | ||
301 | pub enum NameLike { | ||
302 | NameRef(ast::NameRef), | ||
303 | Name(ast::Name), | ||
304 | Lifetime(ast::Lifetime), | ||
305 | } | ||
306 | |||
307 | impl 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 | |||
316 | impl 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 | |||
338 | mod __ { | ||
339 | use super::{ | ||
340 | ast::{Lifetime, Name, NameRef}, | ||
341 | NameLike, | ||
342 | }; | ||
343 | stdx::impl_from!(NameRef, Name, Lifetime for NameLike); | ||
344 | } | ||
345 | |||
300 | #[derive(Debug, Clone, PartialEq)] | 346 | #[derive(Debug, Clone, PartialEq)] |
301 | pub enum NameOrNameRef { | 347 | pub enum NameOrNameRef { |
302 | Name(ast::Name), | 348 | Name(ast::Name), |