Skip to content

Commit 4054525

Browse files
bors[bot]Veykril
andauthored
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]>
2 parents 056601b + e1dbf43 commit 4054525

File tree

6 files changed

+118
-115
lines changed

6 files changed

+118
-115
lines changed

crates/hir_expand/src/name.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,18 @@ impl AsName for ast::Name {
8787
}
8888
}
8989

90-
impl AsName for ast::NameOrNameRef {
90+
impl AsName for ast::Lifetime {
91+
fn as_name(&self) -> Name {
92+
Name::resolve(self.text())
93+
}
94+
}
95+
96+
impl AsName for ast::NameLike {
9197
fn as_name(&self) -> Name {
9298
match self {
93-
ast::NameOrNameRef::Name(it) => it.as_name(),
94-
ast::NameOrNameRef::NameRef(it) => it.as_name(),
99+
ast::NameLike::Name(it) => it.as_name(),
100+
ast::NameLike::NameRef(it) => it.as_name(),
101+
ast::NameLike::Lifetime(it) => it.as_name(),
95102
}
96103
}
97104
}

crates/ide/src/references.rs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -101,29 +101,21 @@ fn find_def(
101101
syntax: &SyntaxNode,
102102
position: FilePosition,
103103
) -> Option<Definition> {
104-
if let Some(name) = sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset)
105-
{
106-
let class = NameClass::classify(sema, &name)?;
107-
Some(class.referenced_or_defined(sema.db))
108-
} else if let Some(lifetime) =
109-
sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset)
110-
{
111-
let def = if let Some(def) =
112-
NameRefClass::classify_lifetime(sema, &lifetime).map(|class| class.referenced(sema.db))
113-
{
114-
def
115-
} else {
116-
NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db)
117-
};
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-
}
104+
let def = match sema.find_node_at_offset_with_descend(syntax, position.offset)? {
105+
ast::NameLike::NameRef(name_ref) => {
106+
NameRefClass::classify(sema, &name_ref)?.referenced(sema.db)
107+
}
108+
ast::NameLike::Name(name) => {
109+
NameClass::classify(sema, &name)?.referenced_or_defined(sema.db)
110+
}
111+
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
112+
.map(|class| class.referenced(sema.db))
113+
.or_else(|| {
114+
NameClass::classify_lifetime(sema, &lifetime)
115+
.map(|class| class.referenced_or_defined(sema.db))
116+
})?,
117+
};
118+
Some(def)
127119
}
128120

129121
fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> {

crates/ide/src/references/rename.rs

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use hir::{HasSource, InFile, Module, ModuleDef, ModuleSource, Semantics};
66
use ide_db::{
77
base_db::{AnchoredPathBuf, FileId},
88
defs::{Definition, NameClass, NameRefClass},
9-
search::{FileReference, NameLike},
9+
search::FileReference,
1010
RootDatabase,
1111
};
1212
use stdx::never;
@@ -47,12 +47,13 @@ pub(crate) fn prepare_rename(
4747
let sema = Semantics::new(db);
4848
let source_file = sema.parse(position.file_id);
4949
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)
5152
.ok_or_else(|| format_err!("No references found at position"))?
5253
{
53-
NameLike::Name(it) => it.syntax(),
54-
NameLike::NameRef(it) => it.syntax(),
55-
NameLike::Lifetime(it) => it.syntax(),
54+
ast::NameLike::Name(it) => it.syntax(),
55+
ast::NameLike::NameRef(it) => it.syntax(),
56+
ast::NameLike::Lifetime(it) => it.syntax(),
5657
}
5758
.text_range();
5859
Ok(RangeInfo::new(range, ()))
@@ -121,50 +122,28 @@ fn check_identifier(new_name: &str) -> RenameResult<IdentifierKind> {
121122
}
122123
}
123124

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-
147125
fn find_definition(
148126
sema: &Semantics<RootDatabase>,
149127
syntax: &SyntaxNode,
150128
position: FilePosition,
151129
) -> RenameResult<Definition> {
152-
match find_name_like(sema, syntax, position)
130+
match sema
131+
.find_node_at_offset_with_descend(syntax, position.offset)
153132
.ok_or_else(|| format_err!("No references found at position"))?
154133
{
155134
// 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)
157136
if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
158137
{
159138
bail!("Renaming aliases is currently unsupported")
160139
}
161-
NameLike::Name(name) => {
140+
ast::NameLike::Name(name) => {
162141
NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db))
163142
}
164-
NameLike::NameRef(name_ref) => {
143+
ast::NameLike::NameRef(name_ref) => {
165144
NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db))
166145
}
167-
NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
146+
ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime)
168147
.map(|class| NameRefClass::referenced(class, sema.db))
169148
.or_else(|| {
170149
NameClass::classify_lifetime(sema, &lifetime)
@@ -187,10 +166,12 @@ fn source_edit_from_references(
187166
// if the ranges differ then the node is inside a macro call, we can't really attempt
188167
// to make special rewrites like shorthand syntax and such, so just rename the node in
189168
// 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+
{
191172
source_edit_from_name_ref(name_ref, new_name, def)
192173
}
193-
NameLike::Name(name) if name.syntax().text_range() == reference.range => {
174+
ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => {
194175
source_edit_from_name(name, new_name)
195176
}
196177
_ => None,

crates/ide_db/src/search.rs

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -52,34 +52,10 @@ impl IntoIterator for UsageSearchResult {
5252
}
5353
}
5454

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-
7955
#[derive(Debug, Clone)]
8056
pub struct FileReference {
8157
pub range: TextRange,
82-
pub name: NameLike,
58+
pub name: ast::NameLike,
8359
pub access: Option<ReferenceAccess>,
8460
}
8561

@@ -300,6 +276,7 @@ impl<'a> FindUsages<'a> {
300276
pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
301277
self.set_scope(Some(scope))
302278
}
279+
303280
pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
304281
assert!(self.scope.is_none());
305282
self.scope = scope;
@@ -355,18 +332,23 @@ impl<'a> FindUsages<'a> {
355332
continue;
356333
}
357334

358-
if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) {
359-
if self.found_name_ref(&name_ref, sink) {
360-
return;
361-
}
362-
} else if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) {
363-
if self.found_name(&name, sink) {
364-
return;
365-
}
366-
} else if let Some(lifetime) = sema.find_node_at_offset_with_descend(&tree, offset)
367-
{
368-
if self.found_lifetime(&lifetime, sink) {
369-
return;
335+
if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) {
336+
match name {
337+
ast::NameLike::NameRef(name_ref) => {
338+
if self.found_name_ref(&name_ref, sink) {
339+
return;
340+
}
341+
}
342+
ast::NameLike::Name(name) => {
343+
if self.found_name(&name, sink) {
344+
return;
345+
}
346+
}
347+
ast::NameLike::Lifetime(lifetime) => {
348+
if self.found_lifetime(&lifetime, sink) {
349+
return;
350+
}
351+
}
370352
}
371353
}
372354
}
@@ -383,7 +365,7 @@ impl<'a> FindUsages<'a> {
383365
let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
384366
let reference = FileReference {
385367
range,
386-
name: NameLike::Lifetime(lifetime.clone()),
368+
name: ast::NameLike::Lifetime(lifetime.clone()),
387369
access: None,
388370
};
389371
sink(file_id, reference)
@@ -402,7 +384,7 @@ impl<'a> FindUsages<'a> {
402384
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
403385
let reference = FileReference {
404386
range,
405-
name: NameLike::NameRef(name_ref.clone()),
387+
name: ast::NameLike::NameRef(name_ref.clone()),
406388
access: reference_access(&def, &name_ref),
407389
};
408390
sink(file_id, reference)
@@ -412,12 +394,12 @@ impl<'a> FindUsages<'a> {
412394
let reference = match self.def {
413395
Definition::Field(_) if &field == self.def => FileReference {
414396
range,
415-
name: NameLike::NameRef(name_ref.clone()),
397+
name: ast::NameLike::NameRef(name_ref.clone()),
416398
access: reference_access(&field, &name_ref),
417399
},
418400
Definition::Local(l) if &local == l => FileReference {
419401
range,
420-
name: NameLike::NameRef(name_ref.clone()),
402+
name: ast::NameLike::NameRef(name_ref.clone()),
421403
access: reference_access(&Definition::Local(local), &name_ref),
422404
},
423405
_ => return false, // not a usage
@@ -441,7 +423,7 @@ impl<'a> FindUsages<'a> {
441423
let FileRange { file_id, range } = self.sema.original_range(name.syntax());
442424
let reference = FileReference {
443425
range,
444-
name: NameLike::Name(name.clone()),
426+
name: ast::NameLike::Name(name.clone()),
445427
// FIXME: mutable patterns should have `Write` access
446428
access: Some(ReferenceAccess::Read),
447429
};

crates/syntax/src/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ pub use self::{
1919
expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
2020
generated::{nodes::*, tokens::*},
2121
node_ext::{
22-
AttrKind, FieldKind, Macro, NameOrNameRef, PathSegmentKind, SelfParamKind,
23-
SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind,
22+
AttrKind, FieldKind, Macro, NameLike, PathSegmentKind, SelfParamKind, SlicePatComponents,
23+
StructKind, TypeBoundKind, VisibilityKind,
2424
},
2525
token_ext::*,
2626
traits::*,

crates/syntax/src/ast/node_ext.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -298,25 +298,66 @@ impl ast::RecordExprField {
298298
}
299299

300300
#[derive(Debug, Clone, PartialEq)]
301-
pub enum NameOrNameRef {
302-
Name(ast::Name),
301+
pub enum NameLike {
303302
NameRef(ast::NameRef),
303+
Name(ast::Name),
304+
Lifetime(ast::Lifetime),
304305
}
305306

306-
impl fmt::Display for NameOrNameRef {
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+
impl fmt::Display for NameLike {
307339
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308340
match self {
309-
NameOrNameRef::Name(it) => fmt::Display::fmt(it, f),
310-
NameOrNameRef::NameRef(it) => fmt::Display::fmt(it, f),
341+
NameLike::Name(it) => fmt::Display::fmt(it, f),
342+
NameLike::NameRef(it) => fmt::Display::fmt(it, f),
343+
NameLike::Lifetime(it) => fmt::Display::fmt(it, f),
311344
}
312345
}
313346
}
314347

348+
mod __ {
349+
use super::{
350+
ast::{Lifetime, Name, NameRef},
351+
NameLike,
352+
};
353+
stdx::impl_from!(NameRef, Name, Lifetime for NameLike);
354+
}
355+
315356
impl ast::RecordPatField {
316357
pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
317358
let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
318359
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),
320361
_ => None,
321362
}
322363
}
@@ -325,19 +366,19 @@ impl ast::RecordPatField {
325366
let candidate =
326367
field_name.syntax().ancestors().nth(2).and_then(ast::RecordPatField::cast)?;
327368
match candidate.field_name()? {
328-
NameOrNameRef::Name(name) if name == *field_name => Some(candidate),
369+
NameLike::Name(name) if name == *field_name => Some(candidate),
329370
_ => None,
330371
}
331372
}
332373

333374
/// Deals with field init shorthand
334-
pub fn field_name(&self) -> Option<NameOrNameRef> {
375+
pub fn field_name(&self) -> Option<NameLike> {
335376
if let Some(name_ref) = self.name_ref() {
336-
return Some(NameOrNameRef::NameRef(name_ref));
377+
return Some(NameLike::NameRef(name_ref));
337378
}
338379
if let Some(ast::Pat::IdentPat(pat)) = self.pat() {
339380
let name = pat.name()?;
340-
return Some(NameOrNameRef::Name(name));
381+
return Some(NameLike::Name(name));
341382
}
342383
None
343384
}

0 commit comments

Comments
 (0)