From d644728d82df10b034d0ea736590c781afa2ba15 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 7 Feb 2021 18:38:12 +0100 Subject: Refactor reference searching to work with the ast --- crates/ide_db/src/search.rs | 140 +++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 80 deletions(-) (limited to 'crates/ide_db/src') diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index b9ba0aed5..d0aed26f7 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs @@ -10,7 +10,9 @@ use base_db::{FileId, FileRange, SourceDatabaseExt}; use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; use once_cell::unsync::Lazy; use rustc_hash::FxHashMap; -use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; +use syntax::{ + ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxNode, TextRange, TextSize, +}; use crate::defs::NameClass; use crate::{ @@ -18,6 +20,13 @@ use crate::{ RootDatabase, }; +#[derive(Debug, Clone)] +pub enum NameKind { + Name, + NameRef, + Lifetime, +} + #[derive(Debug, Default, Clone)] pub struct UsageSearchResult { pub references: FxHashMap>, @@ -52,23 +61,53 @@ impl IntoIterator for UsageSearchResult { } } +#[derive(Debug, Clone)] +pub enum NameLike { + NameRef(ast::NameRef), + Name(ast::Name), + Lifetime(ast::Lifetime), +} + +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 kind: ReferenceKind, + pub name: NameKind, pub access: Option, } -#[derive(Debug, Clone, PartialEq)] -pub enum ReferenceKind { - FieldShorthandForField, - FieldShorthandForLocal, - StructLiteral, - RecordFieldExprOrPat, - SelfParam, - EnumLiteral, - Lifetime, - Other, +impl FileReference { + pub fn name_from_syntax(&self, root: &SyntaxNode) -> Option { + let node = node_or_parent(root.covering_element(self.range)); + match self.name { + NameKind::Name => ast::Name::cast(node).map(Into::into), + NameKind::NameRef => ast::NameRef::cast(node).map(Into::into), + NameKind::Lifetime => ast::Lifetime::cast(node).map(Into::into), + } + } + + pub fn as_name_ref(&self, root: &SyntaxNode) -> Option { + match self.name { + NameKind::NameRef => { + ast::NameRef::cast(node_or_parent(root.covering_element(self.range))) + } + _ => None, + } + } +} + +fn node_or_parent(ele: SyntaxElement) -> SyntaxNode { + match ele { + NodeOrToken::Node(node) => node, + NodeOrToken::Token(token) => token.parent(), + } } #[derive(Debug, Copy, Clone, PartialEq)] @@ -369,8 +408,7 @@ impl<'a> FindUsages<'a> { match NameRefClass::classify_lifetime(self.sema, lifetime) { Some(NameRefClass::Definition(def)) if &def == self.def => { let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); - let reference = - FileReference { range, kind: ReferenceKind::Lifetime, access: None }; + let reference = FileReference { range, name: NameKind::Lifetime, access: None }; sink(file_id, reference) } _ => false, // not a usage @@ -384,19 +422,12 @@ impl<'a> FindUsages<'a> { ) -> bool { match NameRefClass::classify(self.sema, &name_ref) { Some(NameRefClass::Definition(def)) if &def == self.def => { - let kind = if is_record_field_expr_or_pat(&name_ref) { - ReferenceKind::RecordFieldExprOrPat - } else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) { - ReferenceKind::StructLiteral - } else if is_enum_lit_name_ref(&name_ref) { - ReferenceKind::EnumLiteral - } else { - ReferenceKind::Other - }; - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); - let reference = - FileReference { range, kind, access: reference_access(&def, &name_ref) }; + let reference = FileReference { + range, + name: NameKind::NameRef, + access: reference_access(&def, &name_ref), + }; sink(file_id, reference) } Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { @@ -404,12 +435,12 @@ impl<'a> FindUsages<'a> { let reference = match self.def { Definition::Field(_) if &field == self.def => FileReference { range, - kind: ReferenceKind::FieldShorthandForField, + name: NameKind::NameRef, access: reference_access(&field, &name_ref), }, Definition::Local(l) if &local == l => FileReference { range, - kind: ReferenceKind::FieldShorthandForLocal, + name: NameKind::NameRef, access: reference_access(&Definition::Local(local), &name_ref), }, _ => return false, // not a usage @@ -433,7 +464,7 @@ impl<'a> FindUsages<'a> { let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { range, - kind: ReferenceKind::FieldShorthandForField, + name: NameKind::Name, // FIXME: mutable patterns should have `Write` access access: Some(ReferenceAccess::Read), }; @@ -473,54 +504,3 @@ fn reference_access(def: &Definition, name_ref: &ast::NameRef) -> Option bool { - name_ref - .syntax() - .ancestors() - .find_map(ast::CallExpr::cast) - .and_then(|c| match c.expr()? { - ast::Expr::PathExpr(p) => { - Some(p.path()?.segment()?.name_ref().as_ref() == Some(name_ref)) - } - _ => None, - }) - .unwrap_or(false) -} - -fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool { - name_ref - .syntax() - .ancestors() - .find_map(ast::RecordExpr::cast) - .and_then(|l| l.path()) - .and_then(|p| p.segment()) - .map(|p| p.name_ref().as_ref() == Some(name_ref)) - .unwrap_or(false) -} - -fn is_record_field_expr_or_pat(name_ref: &ast::NameRef) -> bool { - if let Some(parent) = name_ref.syntax().parent() { - match_ast! { - match parent { - ast::RecordExprField(it) => true, - ast::RecordPatField(_it) => true, - _ => false, - } - } - } else { - false - } -} - -fn is_enum_lit_name_ref(name_ref: &ast::NameRef) -> bool { - name_ref - .syntax() - .ancestors() - .find_map(ast::PathExpr::cast) - .and_then(|p| p.path()) - .and_then(|p| p.qualifier()) - .and_then(|p| p.segment()) - .map(|p| p.name_ref().as_ref() == Some(name_ref)) - .unwrap_or(false) -} -- cgit v1.2.3