From e52bdc55ef05bae8e647a5a0a9f8c3605c4cdd34 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 16 Feb 2021 19:27:08 +0100 Subject: Implement ast::AstNode for NameLike and move it to node_ext --- crates/ide/src/references.rs | 38 +++++++++------------ crates/ide/src/references/rename.rs | 51 +++++++++------------------- crates/ide_db/src/search.rs | 66 ++++++++++++++----------------------- crates/syntax/src/ast.rs | 2 +- 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( syntax: &SyntaxNode, position: FilePosition, ) -> Option { - if let Some(name) = sema.find_node_at_offset_with_descend::(&syntax, position.offset) - { - let class = NameClass::classify(sema, &name)?; - Some(class.referenced_or_defined(sema.db)) - } else if let Some(lifetime) = - sema.find_node_at_offset_with_descend::(&syntax, position.offset) - { - let def = if let Some(def) = - NameRefClass::classify_lifetime(sema, &lifetime).map(|class| class.referenced(sema.db)) - { - def - } else { - NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db) - }; - Some(def) - } else if let Some(name_ref) = - sema.find_node_at_offset_with_descend::(&syntax, position.offset) - { - let class = NameRefClass::classify(sema, &name_ref)?; - Some(class.referenced(sema.db)) - } else { - None - } + let def = match sema.find_node_at_offset_with_descend(syntax, position.offset)? { + ast::NameLike::NameRef(name_ref) => { + NameRefClass::classify(sema, &name_ref)?.referenced(sema.db) + } + ast::NameLike::Name(name) => { + NameClass::classify(sema, &name)?.referenced_or_defined(sema.db) + } + ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) + .map(|class| class.referenced(sema.db)) + .or_else(|| { + NameClass::classify_lifetime(sema, &lifetime) + .map(|class| class.referenced_or_defined(sema.db)) + })?, + }; + Some(def) } fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option { 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}; use ide_db::{ base_db::{AnchoredPathBuf, FileId}, defs::{Definition, NameClass, NameRefClass}, - search::{FileReference, NameLike}, + search::FileReference, RootDatabase, }; use stdx::never; @@ -47,12 +47,13 @@ pub(crate) fn prepare_rename( let sema = Semantics::new(db); let source_file = sema.parse(position.file_id); let syntax = source_file.syntax(); - let range = match &find_name_like(&sema, &syntax, position) + let range = match &sema + .find_node_at_offset_with_descend(&syntax, position.offset) .ok_or_else(|| format_err!("No references found at position"))? { - NameLike::Name(it) => it.syntax(), - NameLike::NameRef(it) => it.syntax(), - NameLike::Lifetime(it) => it.syntax(), + ast::NameLike::Name(it) => it.syntax(), + ast::NameLike::NameRef(it) => it.syntax(), + ast::NameLike::Lifetime(it) => it.syntax(), } .text_range(); Ok(RangeInfo::new(range, ())) @@ -121,50 +122,28 @@ fn check_identifier(new_name: &str) -> RenameResult { } } -fn find_name_like( - sema: &Semantics, - syntax: &SyntaxNode, - position: FilePosition, -) -> Option { - let namelike = if let Some(name_ref) = - sema.find_node_at_offset_with_descend::(syntax, position.offset) - { - NameLike::NameRef(name_ref) - } else if let Some(name) = - sema.find_node_at_offset_with_descend::(syntax, position.offset) - { - NameLike::Name(name) - } else if let Some(lifetime) = - sema.find_node_at_offset_with_descend::(syntax, position.offset) - { - NameLike::Lifetime(lifetime) - } else { - return None; - }; - Some(namelike) -} - fn find_definition( sema: &Semantics, syntax: &SyntaxNode, position: FilePosition, ) -> RenameResult { - match find_name_like(sema, syntax, position) + match sema + .find_node_at_offset_with_descend(syntax, position.offset) .ok_or_else(|| format_err!("No references found at position"))? { // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet - NameLike::Name(name) + ast::NameLike::Name(name) if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => { bail!("Renaming aliases is currently unsupported") } - NameLike::Name(name) => { + ast::NameLike::Name(name) => { NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db)) } - NameLike::NameRef(name_ref) => { + ast::NameLike::NameRef(name_ref) => { NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db)) } - NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) + ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) .map(|class| NameRefClass::referenced(class, sema.db)) .or_else(|| { NameClass::classify_lifetime(sema, &lifetime) @@ -187,10 +166,12 @@ fn source_edit_from_references( // if the ranges differ then the node is inside a macro call, we can't really attempt // to make special rewrites like shorthand syntax and such, so just rename the node in // the macro input - NameLike::NameRef(name_ref) if name_ref.syntax().text_range() == reference.range => { + ast::NameLike::NameRef(name_ref) + if name_ref.syntax().text_range() == reference.range => + { source_edit_from_name_ref(name_ref, new_name, def) } - NameLike::Name(name) if name.syntax().text_range() == reference.range => { + ast::NameLike::Name(name) if name.syntax().text_range() == reference.range => { source_edit_from_name(name, new_name) } _ => 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 @@ -52,34 +52,10 @@ impl IntoIterator for UsageSearchResult { } } -#[derive(Debug, Clone)] -pub enum NameLike { - NameRef(ast::NameRef), - Name(ast::Name), - Lifetime(ast::Lifetime), -} - -impl NameLike { - pub fn as_name_ref(&self) -> Option<&ast::NameRef> { - match self { - NameLike::NameRef(name_ref) => Some(name_ref), - _ => None, - } - } -} - -mod __ { - use super::{ - ast::{Lifetime, Name, NameRef}, - NameLike, - }; - stdx::impl_from!(NameRef, Name, Lifetime for NameLike); -} - #[derive(Debug, Clone)] pub struct FileReference { pub range: TextRange, - pub name: NameLike, + pub name: ast::NameLike, pub access: Option, } @@ -300,6 +276,7 @@ impl<'a> FindUsages<'a> { pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> { self.set_scope(Some(scope)) } + pub fn set_scope(mut self, scope: Option) -> FindUsages<'a> { assert!(self.scope.is_none()); self.scope = scope; @@ -355,18 +332,23 @@ impl<'a> FindUsages<'a> { continue; } - if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) { - if self.found_name_ref(&name_ref, sink) { - return; - } - } else if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { - if self.found_name(&name, sink) { - return; - } - } else if let Some(lifetime) = sema.find_node_at_offset_with_descend(&tree, offset) - { - if self.found_lifetime(&lifetime, sink) { - return; + if let Some(name) = sema.find_node_at_offset_with_descend(&tree, offset) { + match name { + ast::NameLike::NameRef(name_ref) => { + if self.found_name_ref(&name_ref, sink) { + return; + } + } + ast::NameLike::Name(name) => { + if self.found_name(&name, sink) { + return; + } + } + ast::NameLike::Lifetime(lifetime) => { + if self.found_lifetime(&lifetime, sink) { + return; + } + } } } } @@ -383,7 +365,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); let reference = FileReference { range, - name: NameLike::Lifetime(lifetime.clone()), + name: ast::NameLike::Lifetime(lifetime.clone()), access: None, }; sink(file_id, reference) @@ -402,7 +384,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { range, - name: NameLike::NameRef(name_ref.clone()), + name: ast::NameLike::NameRef(name_ref.clone()), access: reference_access(&def, &name_ref), }; sink(file_id, reference) @@ -412,12 +394,12 @@ impl<'a> FindUsages<'a> { let reference = match self.def { Definition::Field(_) if &field == self.def => FileReference { range, - name: NameLike::NameRef(name_ref.clone()), + name: ast::NameLike::NameRef(name_ref.clone()), access: reference_access(&field, &name_ref), }, Definition::Local(l) if &local == l => FileReference { range, - name: NameLike::NameRef(name_ref.clone()), + name: ast::NameLike::NameRef(name_ref.clone()), access: reference_access(&Definition::Local(local), &name_ref), }, _ => return false, // not a usage @@ -441,7 +423,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { range, - name: NameLike::Name(name.clone()), + name: ast::NameLike::Name(name.clone()), // FIXME: mutable patterns should have `Write` access access: Some(ReferenceAccess::Read), }; 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::{ expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp}, generated::{nodes::*, tokens::*}, node_ext::{ - AttrKind, FieldKind, Macro, NameOrNameRef, PathSegmentKind, SelfParamKind, + AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, }, 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 { } } +#[derive(Debug, Clone)] +pub enum NameLike { + NameRef(ast::NameRef), + Name(ast::Name), + Lifetime(ast::Lifetime), +} + +impl NameLike { + pub fn as_name_ref(&self) -> Option<&ast::NameRef> { + match self { + NameLike::NameRef(name_ref) => Some(name_ref), + _ => None, + } + } +} + +impl ast::AstNode for NameLike { + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, SyntaxKind::NAME | SyntaxKind::NAME_REF | SyntaxKind::LIFETIME) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + SyntaxKind::NAME => NameLike::Name(ast::Name { syntax }), + SyntaxKind::NAME_REF => NameLike::NameRef(ast::NameRef { syntax }), + SyntaxKind::LIFETIME => NameLike::Lifetime(ast::Lifetime { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + NameLike::NameRef(it) => it.syntax(), + NameLike::Name(it) => it.syntax(), + NameLike::Lifetime(it) => it.syntax(), + } + } +} + +mod __ { + use super::{ + ast::{Lifetime, Name, NameRef}, + NameLike, + }; + stdx::impl_from!(NameRef, Name, Lifetime for NameLike); +} + #[derive(Debug, Clone, PartialEq)] pub enum NameOrNameRef { Name(ast::Name), -- cgit v1.2.3