From 80a91e6735c62b0fad817fdb651ab06171aa5568 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 2 Jan 2019 22:18:17 +0300 Subject: [PATCH 1/5] add kind to LocalSyntaxPtr --- crates/ra_db/src/syntax_ptr.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/ra_db/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs index dac94dd36d..744cb23523 100644 --- a/crates/ra_db/src/syntax_ptr.rs +++ b/crates/ra_db/src/syntax_ptr.rs @@ -31,6 +31,10 @@ impl LocalSyntaxPtr { pub fn range(self) -> TextRange { self.range } + + pub fn kind(self) -> SyntaxKind { + self.kind + } } #[test] From f534d2132b90fca8c0646cc81f8a60fa20423fe1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 2 Jan 2019 22:38:52 +0300 Subject: [PATCH 2/5] move some logic to navigation target --- crates/ra_analysis/src/imp.rs | 124 +++++++++++++++++++++---- crates/ra_analysis/src/lib.rs | 25 +++-- crates/ra_analysis/src/symbol_index.rs | 91 +----------------- 3 files changed, 127 insertions(+), 113 deletions(-) diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index ff13247de3..5f67c95f69 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -8,11 +8,11 @@ use hir::{ use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; use ra_editor::{self, find_node_at_offset, LocalEdit, Severity}; use ra_syntax::{ - algo::find_covering_node, + algo::{find_covering_node, visit::{visitor, Visitor}}, ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, AstNode, SourceFileNode, SyntaxKind::*, - SyntaxNodeRef, TextRange, TextUnit, + SyntaxNode, SyntaxNodeRef, TextRange, TextUnit, }; use crate::{ @@ -116,12 +116,12 @@ impl db::RootDatabase { }; let decl = decl.borrowed(); let decl_name = decl.name().unwrap(); - let symbol = FileSymbol { + Ok(vec![NavigationTarget { + file_id, name: decl_name.text(), - node_range: decl_name.syntax().range(), + range: decl_name.syntax().range(), kind: MODULE, - }; - Ok(vec![NavigationTarget { file_id, symbol }]) + }]) } /// Returns `Vec` for the same reason as `parent_module` pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable> { @@ -153,14 +153,12 @@ impl db::RootDatabase { let scope = fn_descr.scopes(self); // First try to resolve the symbol locally if let Some(entry) = scope.resolve_local_name(name_ref) { - rr.add_resolution( - position.file_id, - FileSymbol { - name: entry.name().to_string().into(), - node_range: entry.ptr().range(), - kind: NAME, - }, - ); + rr.resolves_to.push(NavigationTarget { + file_id: position.file_id, + name: entry.name().to_string().into(), + range: entry.ptr().range(), + kind: NAME, + }); return Ok(Some(rr)); }; } @@ -182,12 +180,13 @@ impl db::RootDatabase { Some(name) => name.to_string().into(), None => "".into(), }; - let symbol = FileSymbol { + let symbol = NavigationTarget { + file_id, name, - node_range: TextRange::offset_len(0.into(), 0.into()), + range: TextRange::offset_len(0.into(), 0.into()), kind: MODULE, }; - rr.add_resolution(file_id, symbol); + rr.resolves_to.push(symbol); return Ok(Some(rr)); } } @@ -253,8 +252,7 @@ impl db::RootDatabase { } } pub(crate) fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable> { - let file = self.source_file(nav.file_id); - let result = match (nav.symbol.description(&file), nav.symbol.docs(&file)) { + let result = match (nav.description(self), nav.docs(self)) { (Some(desc), Some(docs)) => { Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs) } @@ -511,3 +509,91 @@ impl<'a> FnCallNode<'a> { } } } + +impl NavigationTarget { + fn node(&self, db: &db::RootDatabase) -> Option { + let source_file = db.source_file(self.file_id); + let source_file = source_file.syntax(); + let node = source_file + .descendants() + .find(|node| node.kind() == self.kind && node.range() == self.range)? + .owned(); + Some(node) + } + + fn docs(&self, db: &db::RootDatabase) -> Option { + let node = self.node(db)?; + let node = node.borrowed(); + fn doc_comments<'a, N: ast::DocCommentsOwner<'a>>(node: N) -> Option { + let comments = node.doc_comment_text(); + if comments.is_empty() { + None + } else { + Some(comments) + } + } + + visitor() + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .accept(node)? + } + + /// Get a description of this node. + /// + /// e.g. `struct Name`, `enum Name`, `fn Name` + fn description(&self, db: &db::RootDatabase) -> Option { + // TODO: After type inference is done, add type information to improve the output + let node = self.node(db)?; + let node = node.borrowed(); + // TODO: Refactor to be have less repetition + visitor() + .visit(|node: ast::FnDef| { + let mut string = "fn ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::StructDef| { + let mut string = "struct ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::EnumDef| { + let mut string = "enum ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::TraitDef| { + let mut string = "trait ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::Module| { + let mut string = "mod ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::TypeDef| { + let mut string = "type ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::ConstDef| { + let mut string = "const ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::StaticDef| { + let mut string = "static ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .accept(node)? + } +} diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index a01febf4e0..8247914c0a 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -222,21 +222,31 @@ impl Query { #[derive(Debug)] pub struct NavigationTarget { file_id: FileId, - symbol: FileSymbol, + name: SmolStr, + kind: SyntaxKind, + range: TextRange, } impl NavigationTarget { - pub fn name(&self) -> SmolStr { - self.symbol.name.clone() + fn from_symbol(file_id: FileId, symbol: FileSymbol) -> NavigationTarget { + NavigationTarget { + name: symbol.name.clone(), + kind: symbol.kind.clone(), + file_id, + range: symbol.node_range.clone(), + } + } + pub fn name(&self) -> &SmolStr { + &self.name } pub fn kind(&self) -> SyntaxKind { - self.symbol.kind + self.kind } pub fn file_id(&self) -> FileId { self.file_id } pub fn range(&self) -> TextRange { - self.symbol.node_range + self.range } } @@ -260,7 +270,8 @@ impl ReferenceResolution { } fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) { - self.resolves_to.push(NavigationTarget { file_id, symbol }) + self.resolves_to + .push(NavigationTarget::from_symbol(file_id, symbol)) } } @@ -359,7 +370,7 @@ impl Analysis { pub fn symbol_search(&self, query: Query) -> Cancelable> { let res = symbol_index::world_symbols(&*self.db, query)? .into_iter() - .map(|(file_id, symbol)| NavigationTarget { file_id, symbol }) + .map(|(file_id, symbol)| NavigationTarget::from_symbol(file_id, symbol)) .collect(); Ok(res) } diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index ddcf3d052b..65abaec2e5 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs @@ -5,10 +5,10 @@ use std::{ use fst::{self, Streamer}; use ra_syntax::{ - AstNode, SyntaxNodeRef, SourceFileNode, SmolStr, TextRange, + SyntaxNodeRef, SourceFileNode, SmolStr, TextRange, algo::visit::{visitor, Visitor}, SyntaxKind::{self, *}, - ast::{self, NameOwner, DocCommentsOwner}, + ast::{self, NameOwner}, }; use ra_db::{SyntaxDatabase, SourceRootId, FilesDatabase}; use salsa::ParallelDatabase; @@ -165,91 +165,7 @@ pub(crate) struct FileSymbol { pub(crate) name: SmolStr, pub(crate) node_range: TextRange, pub(crate) kind: SyntaxKind, -} - -impl FileSymbol { - pub(crate) fn docs(&self, file: &SourceFileNode) -> Option { - file.syntax() - .descendants() - .filter(|node| node.kind() == self.kind && node.range() == self.node_range) - .filter_map(|node: SyntaxNodeRef| { - fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option { - let comments = node.doc_comment_text(); - if comments.is_empty() { - None - } else { - Some(comments) - } - } - - visitor() - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .visit(doc_comments::) - .accept(node)? - }) - .nth(0) - } - /// Get a description of this node. - /// - /// e.g. `struct Name`, `enum Name`, `fn Name` - pub(crate) fn description(&self, file: &SourceFileNode) -> Option { - // TODO: After type inference is done, add type information to improve the output - file.syntax() - .descendants() - .filter(|node| node.kind() == self.kind && node.range() == self.node_range) - .filter_map(|node: SyntaxNodeRef| { - // TODO: Refactor to be have less repetition - visitor() - .visit(|node: ast::FnDef| { - let mut string = "fn ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::StructDef| { - let mut string = "struct ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::EnumDef| { - let mut string = "enum ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::TraitDef| { - let mut string = "trait ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::Module| { - let mut string = "mod ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::TypeDef| { - let mut string = "type ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::ConstDef| { - let mut string = "const ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .visit(|node: ast::StaticDef| { - let mut string = "static ".to_string(); - node.name()?.syntax().text().push_to(&mut string); - Some(string) - }) - .accept(node)? - }) - .nth(0) - } + _x: (), } fn to_symbol(node: SyntaxNodeRef) -> Option { @@ -259,6 +175,7 @@ fn to_symbol(node: SyntaxNodeRef) -> Option { name: name.text(), node_range: node.syntax().range(), kind: node.syntax().kind(), + _x: (), }) } visitor() From 267a89bca2b606faafacfe69db7fda1ef27bb39f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 2 Jan 2019 23:24:58 +0300 Subject: [PATCH 3/5] use LocalSyntaxPtr for file symbol --- crates/ra_analysis/src/imp.rs | 80 +++++++++++++------------- crates/ra_analysis/src/lib.rs | 4 +- crates/ra_analysis/src/symbol_index.rs | 14 ++--- 3 files changed, 47 insertions(+), 51 deletions(-) diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 5f67c95f69..7604c7def4 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -360,52 +360,52 @@ impl db::RootDatabase { // Resolve the function's NameRef (NOTE: this isn't entirely accurate). let file_symbols = self.index_resolve(name_ref)?; for (fn_file_id, fs) in file_symbols { - if fs.kind == FN_DEF { + if fs.ptr.kind() == FN_DEF { let fn_file = self.source_file(fn_file_id); - if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { - let descr = ctry!(source_binder::function_from_source( - self, fn_file_id, fn_def - )?); - if let Some(descriptor) = descr.signature_info(self) { - // If we have a calling expression let's find which argument we are on - let mut current_parameter = None; + let fn_def = fs.ptr.resolve(&fn_file); + let fn_def = ast::FnDef::cast(fn_def.borrowed()).unwrap(); + let descr = ctry!(source_binder::function_from_source( + self, fn_file_id, fn_def + )?); + if let Some(descriptor) = descr.signature_info(self) { + // If we have a calling expression let's find which argument we are on + let mut current_parameter = None; - let num_params = descriptor.params.len(); - let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); + let num_params = descriptor.params.len(); + let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); - if num_params == 1 { - if !has_self { - current_parameter = Some(0); - } - } else if num_params > 1 { - // Count how many parameters into the call we are. - // TODO: This is best effort for now and should be fixed at some point. - // It may be better to see where we are in the arg_list and then check - // where offset is in that list (or beyond). - // Revisit this after we get documentation comments in. - if let Some(ref arg_list) = calling_node.arg_list() { - let start = arg_list.syntax().range().start(); - - let range_search = TextRange::from_to(start, position.offset); - let mut commas: usize = arg_list - .syntax() - .text() - .slice(range_search) - .to_string() - .matches(',') - .count(); - - // If we have a method call eat the first param since it's just self. - if has_self { - commas += 1; - } - - current_parameter = Some(commas); - } + if num_params == 1 { + if !has_self { + current_parameter = Some(0); } + } else if num_params > 1 { + // Count how many parameters into the call we are. + // TODO: This is best effort for now and should be fixed at some point. + // It may be better to see where we are in the arg_list and then check + // where offset is in that list (or beyond). + // Revisit this after we get documentation comments in. + if let Some(ref arg_list) = calling_node.arg_list() { + let start = arg_list.syntax().range().start(); - return Ok(Some((descriptor, current_parameter))); + let range_search = TextRange::from_to(start, position.offset); + let mut commas: usize = arg_list + .syntax() + .text() + .slice(range_search) + .to_string() + .matches(',') + .count(); + + // If we have a method call eat the first param since it's just self. + if has_self { + commas += 1; + } + + current_parameter = Some(commas); + } } + + return Ok(Some((descriptor, current_parameter))); } } } diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 8247914c0a..69d6754d6a 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -231,9 +231,9 @@ impl NavigationTarget { fn from_symbol(file_id: FileId, symbol: FileSymbol) -> NavigationTarget { NavigationTarget { name: symbol.name.clone(), - kind: symbol.kind.clone(), + kind: symbol.ptr.kind(), file_id, - range: symbol.node_range.clone(), + range: symbol.ptr.range(), } } pub fn name(&self) -> &SmolStr { diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 65abaec2e5..1b6815bbfd 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs @@ -5,12 +5,12 @@ use std::{ use fst::{self, Streamer}; use ra_syntax::{ - SyntaxNodeRef, SourceFileNode, SmolStr, TextRange, + SyntaxNodeRef, SourceFileNode, SmolStr, algo::visit::{visitor, Visitor}, SyntaxKind::{self, *}, ast::{self, NameOwner}, }; -use ra_db::{SyntaxDatabase, SourceRootId, FilesDatabase}; +use ra_db::{SyntaxDatabase, SourceRootId, FilesDatabase, LocalSyntaxPtr}; use salsa::ParallelDatabase; use rayon::prelude::*; @@ -140,7 +140,7 @@ impl Query { let idx = indexed_value.value as usize; let (file_id, symbol) = &file_symbols.symbols[idx]; - if self.only_types && !is_type(symbol.kind) { + if self.only_types && !is_type(symbol.ptr.kind()) { continue; } if self.exact && symbol.name != self.query { @@ -163,9 +163,7 @@ fn is_type(kind: SyntaxKind) -> bool { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct FileSymbol { pub(crate) name: SmolStr, - pub(crate) node_range: TextRange, - pub(crate) kind: SyntaxKind, - _x: (), + pub(crate) ptr: LocalSyntaxPtr, } fn to_symbol(node: SyntaxNodeRef) -> Option { @@ -173,9 +171,7 @@ fn to_symbol(node: SyntaxNodeRef) -> Option { let name = node.name()?; Some(FileSymbol { name: name.text(), - node_range: node.syntax().range(), - kind: node.syntax().kind(), - _x: (), + ptr: LocalSyntaxPtr::new(node.syntax()), }) } visitor() From 03ea6bcbffd4ae3ac5289ff7d434450c219186a8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 2 Jan 2019 23:35:51 +0300 Subject: [PATCH 4/5] use LocalPtr in navigation target --- crates/ra_analysis/src/imp.rs | 3 +++ crates/ra_analysis/src/lib.rs | 5 ++++- crates/ra_analysis/tests/tests.rs | 10 +++++----- crates/ra_lsp_server/src/main_loop/handlers.rs | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 7604c7def4..b812c34410 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -121,6 +121,7 @@ impl db::RootDatabase { name: decl_name.text(), range: decl_name.syntax().range(), kind: MODULE, + ptr: None, }]) } /// Returns `Vec` for the same reason as `parent_module` @@ -158,6 +159,7 @@ impl db::RootDatabase { name: entry.name().to_string().into(), range: entry.ptr().range(), kind: NAME, + ptr: None, }); return Ok(Some(rr)); }; @@ -185,6 +187,7 @@ impl db::RootDatabase { name, range: TextRange::offset_len(0.into(), 0.into()), kind: MODULE, + ptr: None, }; rr.resolves_to.push(symbol); return Ok(Some(rr)); diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 69d6754d6a..343fd28bb8 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -41,7 +41,7 @@ pub use ra_editor::{ pub use hir::FnSignatureInfo; pub use ra_db::{ - Canceled, Cancelable, FilePosition, FileRange, + Canceled, Cancelable, FilePosition, FileRange, LocalSyntaxPtr, CrateGraph, CrateId, SourceRootId, FileId, SyntaxDatabase, FilesDatabase }; @@ -225,6 +225,8 @@ pub struct NavigationTarget { name: SmolStr, kind: SyntaxKind, range: TextRange, + // Should be DefId ideally + ptr: Option, } impl NavigationTarget { @@ -234,6 +236,7 @@ impl NavigationTarget { kind: symbol.ptr.kind(), file_id, range: symbol.ptr.range(), + ptr: Some(symbol.ptr.clone()), } } pub fn name(&self) -> &SmolStr { diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 3045c2e781..bcf29d29ca 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs @@ -25,7 +25,7 @@ fn approximate_resolve_works_in_items() { assert_eq_dbg( r#"ReferenceResolution { reference_range: [23; 26), - resolves_to: [NavigationTarget { file_id: FileId(1), symbol: FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF } }] + resolves_to: [NavigationTarget { file_id: FileId(1), name: "Foo", kind: STRUCT_DEF, range: [0; 11), ptr: Some(LocalSyntaxPtr { range: [0; 11), kind: STRUCT_DEF }) }] }"#, &symbols, ); @@ -46,7 +46,7 @@ fn test_resolve_module() { assert_eq_dbg( r#"ReferenceResolution { reference_range: [4; 7), - resolves_to: [NavigationTarget { file_id: FileId(2), symbol: FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE } }] + resolves_to: [NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }] }"#, &symbols, ); @@ -64,7 +64,7 @@ fn test_resolve_module() { assert_eq_dbg( r#"ReferenceResolution { reference_range: [4; 7), - resolves_to: [NavigationTarget { file_id: FileId(2), symbol: FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE } }] + resolves_to: [NavigationTarget { file_id: FileId(2), name: "foo", kind: MODULE, range: [0; 0), ptr: None }] }"#, &symbols, ); @@ -107,7 +107,7 @@ fn test_resolve_parent_module() { ); let symbols = analysis.parent_module(pos).unwrap(); assert_eq_dbg( - r#"[NavigationTarget { file_id: FileId(1), symbol: FileSymbol { name: "foo", node_range: [4; 7), kind: MODULE } }]"#, + r#"[NavigationTarget { file_id: FileId(1), name: "foo", kind: MODULE, range: [4; 7), ptr: None }]"#, &symbols, ); } @@ -126,7 +126,7 @@ fn test_resolve_parent_module_for_inline() { ); let symbols = analysis.parent_module(pos).unwrap(); assert_eq_dbg( - r#"[NavigationTarget { file_id: FileId(1), symbol: FileSymbol { name: "bar", node_range: [18; 21), kind: MODULE } }]"#, + r#"[NavigationTarget { file_id: FileId(1), name: "bar", kind: MODULE, range: [18; 21), ptr: None }]"#, &symbols, ); } diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 26b6c7d8a5..b5792f3b81 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -190,7 +190,7 @@ pub fn handle_workspace_symbol( let mut res = Vec::new(); for nav in world.analysis().symbol_search(query)? { let info = SymbolInformation { - name: nav.name().into(), + name: nav.name().to_string(), kind: nav.kind().conv(), location: nav.try_conv_with(world)?, container_name: None, From 8d6185350953391d0dd405cf790a69bb65d88a36 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 3 Jan 2019 12:57:30 +0300 Subject: [PATCH 5/5] docs --- crates/ra_analysis/src/lib.rs | 13 ++++++++++--- crates/ra_analysis/src/symbol_index.rs | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 343fd28bb8..61af676b2c 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -1,6 +1,8 @@ -//! ra_analyzer crate is the brain of Rust analyzer. It relies on the `salsa` -//! crate, which provides and incremental on-demand database of facts. - +//! ra_analyzer crate provides "ide-centric" APIs for the rust-analyzer. What +//! powers this API are the `RootDatabase` struct, which defines a `salsa` +//! database, and the `ra_hir` crate, where majority of the analysis happens. +//! However, IDE specific bits of the analysis (most notably completion) happen +//! in this crate. macro_rules! ctry { ($expr:expr) => { match $expr { @@ -219,6 +221,11 @@ impl Query { } } +/// `NavigationTarget` represents and element in the editor's UI whihc you can +/// click on to navigate to a particular piece of code. +/// +/// Typically, a `NavigationTarget` corresponds to some element in the source +/// code, like a function or a struct, but this is not strictly required. #[derive(Debug)] pub struct NavigationTarget { file_id: FileId, diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 1b6815bbfd..10d8e80599 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs @@ -1,3 +1,24 @@ +//! This module handles fuzzy-searching of functions, structs and other symbols +//! by name across the whole workspace and dependencies. +//! +//! It works by building an incrementally-updated text-search index of all +//! symbols. The backbone of the index is the **awesome** `fst` crate by +//! @BurntSushi. +//! +//! In a nutshell, you give a set of strings to the `fst`, and it builds a +//! finite state machine describing this set of strtings. The strings which +//! could fuzzy-match a pattern can also be described by a finite state machine. +//! What is freakingly cool is that you can now traverse both state machines in +//! lock-step to enumerate the strings which are both in the input set and +//! fuzz-match the query. Or, more formally, given two langauges described by +//! fsts, one can build an product fst which describes the intersection of the +//! languages. +//! +//! `fst` does not support cheap updating of the index, but it supports unioning +//! of state machines. So, to account for changing source code, we build an fst +//! for each library (which is assumed to never change) and an fst for each rust +//! file in the current workspace, and run a query aginst the union of all +//! thouse fsts. use std::{ hash::{Hash, Hasher}, sync::Arc, @@ -160,6 +181,8 @@ fn is_type(kind: SyntaxKind) -> bool { } } +/// The actual data that is stored in the index. It should be as compact as +/// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct FileSymbol { pub(crate) name: SmolStr,