diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 034a5117933..970d37b9cbd 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -364,8 +364,8 @@ pub fn folding_ranges(&self, file_id: FileId) -> Cancellable> { pub fn symbol_search(&self, query: Query) -> Cancellable> { self.with_db(|db| { symbol_index::world_symbols(db, query) - .into_iter() - .map(|s| s.to_nav(db)) + .into_iter() // xx: should we make this a par iter? + .filter_map(|s| s.try_to_nav(db)) .collect::>() }) } diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index a566a758937..76ec99ce9e8 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -167,10 +167,14 @@ fn from_syntax( } } -impl ToNav for FileSymbol { - fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { - NavigationTarget { - file_id: self.original_file_id, +impl TryToNav for FileSymbol { + fn try_to_nav(&self, db: &RootDatabase) -> Option { + let semantics = Semantics::new(db); + let full_range = self.loc.original_range(&semantics)?; + let name_range = self.loc.original_name_range(&semantics)?; + + Some(NavigationTarget { + file_id: full_range.file_id, name: self.name.clone(), kind: Some(match self.kind { FileSymbolKind::Function => SymbolKind::Function, @@ -184,12 +188,12 @@ fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { FileSymbolKind::Macro => SymbolKind::Macro, FileSymbolKind::Union => SymbolKind::Union, }), - full_range: self.range, - focus_range: self.name_range, + full_range: full_range.range, + focus_range: Some(name_range.range), container_name: self.container_name.clone(), description: description_from_symbol(db, self), docs: None, - } + }) } } @@ -517,8 +521,7 @@ fn try_to_nav(&self, db: &RootDatabase) -> Option { /// e.g. `struct Name`, `enum Name`, `fn Name` pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option { let sema = Semantics::new(db); - let syntax = sema.parse_or_expand(symbol.hir_file_id)?; - let node = symbol.ptr.to_node(&syntax); + let node = symbol.loc.syntax(&sema)?; match_ast! { match node { diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs index fb62d2e7d70..e0dbe6caf0a 100644 --- a/crates/ide_db/src/items_locator.rs +++ b/crates/ide_db/src/items_locator.rs @@ -133,9 +133,8 @@ fn get_name_definition( import_candidate: &FileSymbol, ) -> Option { let _p = profile::span("get_name_definition"); - let file_id = import_candidate.hir_file_id; - let candidate_node = import_candidate.ptr.to_node(&sema.parse_or_expand(file_id)?); + let candidate_node = import_candidate.loc.syntax(sema)?; let candidate_name_node = if candidate_node.kind() != NAME { candidate_node.children().find(|it| it.kind() == NAME)? } else { diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 401056aaaf3..93d00118dc8 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs @@ -30,20 +30,18 @@ use base_db::{ salsa::{self, ParallelDatabase}, - CrateId, FileId, SourceDatabaseExt, SourceRootId, + CrateId, FileId, FileRange, SourceDatabaseExt, SourceRootId, Upcast, }; use fst::{self, Streamer}; use hir::{ - db::DefDatabase, AdtId, AssocContainerId, AssocItemLoc, DefHasSource, HirFileId, ItemLoc, - ItemScope, ItemTreeNode, Lookup, ModuleData, ModuleDefId, ModuleId, + db::DefDatabase, AdtId, AssocContainerId, AssocItemLoc, DefHasSource, HirFileId, InFile, + ItemLoc, ItemScope, ItemTreeNode, Lookup, ModuleData, ModuleDefId, ModuleId, Semantics, }; use rayon::prelude::*; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ ast::{self, HasName}, - match_ast, AstNode, Parse, SmolStr, SourceFile, - SyntaxKind::*, - SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, + AstNode, Parse, SmolStr, SourceFile, SyntaxNode, SyntaxNodePtr, }; use crate::RootDatabase; @@ -371,16 +369,52 @@ pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec { /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FileSymbol { - pub hir_file_id: HirFileId, - pub original_file_id: FileId, pub name: SmolStr, + pub loc: DeclarationLocation, pub kind: FileSymbolKind, - pub range: TextRange, - pub ptr: SyntaxNodePtr, - pub name_range: Option, pub container_name: Option, } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DeclarationLocation { + /// The file id for both the `ptr` and `name_ptr`. + pub hir_file_id: HirFileId, + /// This points to the whole syntax node of the declaration. + pub ptr: SyntaxNodePtr, + /// This points to the [`syntax::ast::Name`] identifier of the declaration. + pub name_ptr: SyntaxNodePtr, +} + +impl DeclarationLocation { + pub fn syntax(&self, semantics: &Semantics<'_, RootDatabase>) -> Option { + let root = semantics.parse_or_expand(self.hir_file_id)?; + Some(self.ptr.to_node(&root)) + } + + pub fn original_range(&self, semantics: &Semantics<'_, RootDatabase>) -> Option { + find_original_file_range(semantics, self.hir_file_id, &self.ptr) + } + + pub fn original_name_range( + &self, + semantics: &Semantics<'_, RootDatabase>, + ) -> Option { + find_original_file_range(semantics, self.hir_file_id, &self.name_ptr) + } +} + +fn find_original_file_range( + semantics: &Semantics<'_, RootDatabase>, + file_id: HirFileId, + ptr: &SyntaxNodePtr, +) -> Option { + let root = semantics.parse_or_expand(file_id)?; + let node = ptr.to_node(&root); + let node = InFile::new(file_id, &node); + + Some(node.original_file_range(semantics.db.upcast())) +} + #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum FileSymbolKind { Const, @@ -408,82 +442,9 @@ fn is_type(self: FileSymbolKind) -> bool { } } -fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec { - let mut symbols = Vec::new(); - let mut stack = Vec::new(); - - for event in source_file.syntax().preorder() { - match event { - WalkEvent::Enter(node) => { - if let Some(mut symbol) = to_file_symbol(&node, file_id) { - symbol.container_name = stack.last().cloned(); - - stack.push(symbol.name.clone()); - symbols.push(symbol); - } - } - - WalkEvent::Leave(node) => { - if to_symbol(&node).is_some() { - stack.pop(); - } - } - } - } - - symbols -} - -fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { - fn decl(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { - let name = node.name()?; - let name_range = name.syntax().text_range(); - let name = name.text().into(); - let ptr = SyntaxNodePtr::new(node.syntax()); - - Some((name, ptr, name_range)) - } - match_ast! { - match node { - ast::Fn(it) => decl(it), - ast::Struct(it) => decl(it), - ast::Enum(it) => decl(it), - ast::Trait(it) => decl(it), - ast::Module(it) => decl(it), - ast::TypeAlias(it) => decl(it), - ast::Const(it) => decl(it), - ast::Static(it) => decl(it), - ast::Macro(it) => decl(it), - ast::Union(it) => decl(it), - _ => None, - } - } -} - -fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option { - to_symbol(node).map(move |(name, ptr, name_range)| FileSymbol { - name, - kind: match node.kind() { - FN => FileSymbolKind::Function, // FunctionId - STRUCT => FileSymbolKind::Struct, // AdtId::StructId - ENUM => FileSymbolKind::Enum, // AdtId::EnumId - TRAIT => FileSymbolKind::Trait, // TraitId - MODULE => FileSymbolKind::Module, // ModuleId - TYPE_ALIAS => FileSymbolKind::TypeAlias, // TypeAliasId - CONST => FileSymbolKind::Const, // ConstId - STATIC => FileSymbolKind::Static, // StaticId - MACRO_RULES => FileSymbolKind::Macro, // via ItemScope::macros - MACRO_DEF => FileSymbolKind::Macro, // via ItemScope::macros - UNION => FileSymbolKind::Union, // AdtId::UnionId - kind => unreachable!("{:?}", kind), - }, - range: node.text_range(), - ptr, - hir_file_id: file_id.into(), - original_file_id: file_id, - name_range: Some(name_range), - container_name: None, - }) +fn source_file_to_file_symbols(_source_file: &SourceFile, _file_id: FileId) -> Vec { + // todo: delete this. + vec![] } fn module_data_to_file_symbols(db: &dyn DefDatabase, module_data: &ModuleData) -> Vec { @@ -498,24 +459,8 @@ fn collect_symbols_from_item_scope( symbols: &mut Vec, scope: &ItemScope, ) { - // todo: dedupe code. - fn decl_assoc(db: &dyn DefDatabase, id: L, kind: FileSymbolKind) -> Option - where - L: Lookup>, - T: ItemTreeNode, - ::Source: HasName, - { - let loc = id.lookup(db); - let source = loc.source(db); - - let name = source.value.name()?; - let name_range = source.with_value(name.syntax()).original_file_range(db.upcast()); - let hir_file_id = loc.id.file_id(); - - let name = name.text().into(); - let ptr = SyntaxNodePtr::new(source.value.syntax()); - - let container_name = match loc.container { + fn container_name(db: &dyn DefDatabase, container: AssocContainerId) -> Option { + match container { AssocContainerId::ModuleId(module_id) => { let def_map = module_id.def_map(db); let module_data = &def_map[module_id.local_id]; @@ -530,19 +475,32 @@ fn decl_assoc(db: &dyn DefDatabase, id: L, kind: FileSymbolKind) -> Option source.value.name().map(|n| n.text().into()) } AssocContainerId::ImplId(_) => None, - }; + } + } + + fn decl_assoc(db: &dyn DefDatabase, id: L, kind: FileSymbolKind) -> Option + where + L: Lookup>, + T: ItemTreeNode, + ::Source: HasName, + { + let loc = id.lookup(db); + let source = loc.source(db); + let name_node = source.value.name()?; + let container_name = container_name(db, loc.container); Some(FileSymbol { - name, + name: name_node.text().into(), kind, - range: source.with_value(source.value.syntax()).original_file_range(db.upcast()).range, container_name, - hir_file_id, - original_file_id: name_range.file_id, - name_range: Some(name_range.range), - ptr, + loc: DeclarationLocation { + hir_file_id: source.file_id, + ptr: SyntaxNodePtr::new(source.value.syntax()), + name_ptr: SyntaxNodePtr::new(name_node.syntax()), + }, }) } + fn decl(db: &dyn DefDatabase, id: L, kind: FileSymbolKind) -> Option where L: Lookup>, @@ -551,21 +509,17 @@ fn decl(db: &dyn DefDatabase, id: L, kind: FileSymbolKind) -> Option Option let def_map = module_id.def_map(db); let module_data = &def_map[module_id.local_id]; let declaration = module_data.origin.declaration()?; - let hir_file_id = declaration.file_id; - let module = declaration.to_node(db.upcast()); - let name = module.name()?; - let name_range = declaration.with_value(name.syntax()).original_file_range(db.upcast()); - let name = name.text().into(); - let ptr = SyntaxNodePtr::new(module.syntax()); + let name_node = module.name()?; Some(FileSymbol { - name, + name: name_node.text().into(), kind: FileSymbolKind::Module, - range: declaration.with_value(module.syntax()).original_file_range(db.upcast()).range, container_name: None, - hir_file_id, - original_file_id: name_range.file_id, - name_range: Some(name_range.range), - ptr, + loc: DeclarationLocation { + hir_file_id: declaration.file_id, + ptr: SyntaxNodePtr::new(module.syntax()), + name_ptr: SyntaxNodePtr::new(name_node.syntax()), + }, }) }